var THREE = THREE || { REVISION: '59' };
self.console = self.console || {
	info: function () {},
	log: function () {},
	debug: function () {},
	warn: function () {},
	error: function () {}
};
String.prototype.trim = String.prototype.trim || function () {
	return this.replace( /^\s+|\s+$/g, '' );
};
THREE.extend = function ( obj, source ) {
		if ( Object.keys ) {
		var keys = Object.keys( source );
		for (var i = 0, il = keys.length; i < il; i++) {
			var prop = keys[i];
			Object.defineProperty( obj, prop, Object.getOwnPropertyDescriptor( source, prop ) );
		}
	} else {
		var safeHasOwnProperty = {}.hasOwnProperty;
		for ( var prop in source ) {
			if ( safeHasOwnProperty.call( source, prop ) ) {
				obj[prop] = source[prop];
			}
		}
	}
	return obj;
};
( function () {
	var lastTime = 0;
	var vendors = [ 'ms', 'moz', 'webkit', 'o' ];
	for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) {
		self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ];
		self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ];
	}
	if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) {
		self.requestAnimationFrame = function ( callback ) {
			var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
			var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall );
			lastTime = currTime + timeToCall;
			return id;
		};
	}
	if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) {
		self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) };
	}
}() );
THREE.CullFaceNone = 0;
THREE.CullFaceBack = 1;
THREE.CullFaceFront = 2;
THREE.CullFaceFrontBack = 3;
THREE.FrontFaceDirectionCW = 0;
THREE.FrontFaceDirectionCCW = 1;
THREE.BasicShadowMap = 0;
THREE.PCFShadowMap = 1;
THREE.PCFSoftShadowMap = 2;
THREE.FrontSide = 0;
THREE.BackSide = 1;
THREE.DoubleSide = 2;
THREE.NoShading = 0;
THREE.FlatShading = 1;
THREE.SmoothShading = 2;
THREE.NoColors = 0;
THREE.FaceColors = 1;
THREE.VertexColors = 2;
THREE.NoBlending = 0;
THREE.NormalBlending = 1;
THREE.AdditiveBlending = 2;
THREE.SubtractiveBlending = 3;
THREE.MultiplyBlending = 4;
THREE.CustomBlending = 5;
THREE.AddEquation = 100;
THREE.SubtractEquation = 101;
THREE.ReverseSubtractEquation = 102;
THREE.ZeroFactor = 200;
THREE.OneFactor = 201;
THREE.SrcColorFactor = 202;
THREE.OneMinusSrcColorFactor = 203;
THREE.SrcAlphaFactor = 204;
THREE.OneMinusSrcAlphaFactor = 205;
THREE.DstAlphaFactor = 206;
THREE.OneMinusDstAlphaFactor = 207;
THREE.DstColorFactor = 208;
THREE.OneMinusDstColorFactor = 209;
THREE.SrcAlphaSaturateFactor = 210;
THREE.MultiplyOperation = 0;
THREE.MixOperation = 1;
THREE.AddOperation = 2;
THREE.UVMapping = function () {};
THREE.CubeReflectionMapping = function () {};
THREE.CubeRefractionMapping = function () {};
THREE.SphericalReflectionMapping = function () {};
THREE.SphericalRefractionMapping = function () {};
THREE.RepeatWrapping = 1000;
THREE.ClampToEdgeWrapping = 1001;
THREE.MirroredRepeatWrapping = 1002;
THREE.NearestFilter = 1003;
THREE.NearestMipMapNearestFilter = 1004;
THREE.NearestMipMapLinearFilter = 1005;
THREE.LinearFilter = 1006;
THREE.LinearMipMapNearestFilter = 1007;
THREE.LinearMipMapLinearFilter = 1008;
THREE.UnsignedByteType = 1009;
THREE.ByteType = 1010;
THREE.ShortType = 1011;
THREE.UnsignedShortType = 1012;
THREE.IntType = 1013;
THREE.UnsignedIntType = 1014;
THREE.FloatType = 1015;
THREE.UnsignedShort4444Type = 1016;
THREE.UnsignedShort5551Type = 1017;
THREE.UnsignedShort565Type = 1018;
THREE.AlphaFormat = 1019;
THREE.RGBFormat = 1020;
THREE.RGBAFormat = 1021;
THREE.LuminanceFormat = 1022;
THREE.LuminanceAlphaFormat = 1023;
THREE.RGB_S3TC_DXT1_Format = 2001;
THREE.RGBA_S3TC_DXT1_Format = 2002;
THREE.RGBA_S3TC_DXT3_Format = 2003;
THREE.RGBA_S3TC_DXT5_Format = 2004;
THREE.Color = function ( value ) {
	if ( value !== undefined ) this.set( value );
	return this;
};
THREE.Color.prototype = {
	constructor: THREE.Color,
	r: 1, g: 1, b: 1,
	set: function ( value ) {
		if ( value instanceof THREE.Color ) {
			this.copy( value );
		} else if ( typeof value === 'number' ) {
			this.setHex( value );
		} else if ( typeof value === 'string' ) {
			this.setStyle( value );
		}
		return this;
	},
	setHex: function ( hex ) {
		hex = Math.floor( hex );
		this.r = ( hex >> 16 & 255 ) / 255;
		this.g = ( hex >> 8 & 255 ) / 255;
		this.b = ( hex & 255 ) / 255;
		return this;
	},
	setRGB: function ( r, g, b ) {
		this.r = r;
		this.g = g;
		this.b = b;
		return this;
	},
	setHSL: function ( h, s, l ) {
				if ( s === 0 ) {
			this.r = this.g = this.b = l;
		} else {
			var hue2rgb = function ( p, q, t ) {
				if ( t < 0 ) t += 1;
				if ( t > 1 ) t -= 1;
				if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
				if ( t < 1 / 2 ) return q;
				if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
				return p;
			};
			var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
			var q = ( 2 * l ) - p;
			this.r = hue2rgb( q, p, h + 1 / 3 );
			this.g = hue2rgb( q, p, h );
			this.b = hue2rgb( q, p, h - 1 / 3 );
		}
		return this;
	},
	setStyle: function ( style ) {
				if ( /^rgb\((\d+),(\d+),(\d+)\)$/i.test( style ) ) {
			var color = /^rgb\((\d+),(\d+),(\d+)\)$/i.exec( style );
			this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
			this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
			this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
			return this;
		}
				if ( /^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.test( style ) ) {
			var color = /^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.exec( style );
			this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
			this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
			this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
			return this;
		}
				if ( /^\#([0-9a-f]{6})$/i.test( style ) ) {
			var color = /^\#([0-9a-f]{6})$/i.exec( style );
			this.setHex( parseInt( color[ 1 ], 16 ) );
			return this;
		}
				if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) {
			var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style );
			this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) );
			return this;
		}
				if ( /^(\w+)$/i.test( style ) ) {
			this.setHex( THREE.ColorKeywords[ style ] );
			return this;
		}
	},
	copy: function ( color ) {
		this.r = color.r;
		this.g = color.g;
		this.b = color.b;
		return this;
	},
	copyGammaToLinear: function ( color ) {
		this.r = color.r * color.r;
		this.g = color.g * color.g;
		this.b = color.b * color.b;
		return this;
	},
	copyLinearToGamma: function ( color ) {
		this.r = Math.sqrt( color.r );
		this.g = Math.sqrt( color.g );
		this.b = Math.sqrt( color.b );
		return this;
	},
	convertGammaToLinear: function () {
		var r = this.r, g = this.g, b = this.b;
		this.r = r * r;
		this.g = g * g;
		this.b = b * b;
		return this;
	},
	convertLinearToGamma: function () {
		this.r = Math.sqrt( this.r );
		this.g = Math.sqrt( this.g );
		this.b = Math.sqrt( this.b );
		return this;
	},
	getHex: function () {
		return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
	},
	getHexString: function () {
		return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
	},
	getHSL: function () {
		var hsl = { h: 0, s: 0, l: 0 };
		return function () {
						var r = this.r, g = this.g, b = this.b;
			var max = Math.max( r, g, b );
			var min = Math.min( r, g, b );
			var hue, saturation;
			var lightness = ( min + max ) / 2.0;
			if ( min === max ) {
				hue = 0;
				saturation = 0;
			} else {
				var delta = max - min;
				saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
				switch ( max ) {
					case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
					case g: hue = ( b - r ) / delta + 2; break;
					case b: hue = ( r - g ) / delta + 4; break;
				}
				hue /= 6;
			}
			hsl.h = hue;
			hsl.s = saturation;
			hsl.l = lightness;
			return hsl;
		};
	}(),
	getStyle: function () {
		return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
	},
	offsetHSL: function ( h, s, l ) {
		var hsl = this.getHSL();
		hsl.h += h; hsl.s += s; hsl.l += l;
		this.setHSL( hsl.h, hsl.s, hsl.l );
		return this;
	},
	add: function ( color ) {
		this.r += color.r;
		this.g += color.g;
		this.b += color.b;
		return this;
	},
	addColors: function ( color1, color2 ) {
		this.r = color1.r + color2.r;
		this.g = color1.g + color2.g;
		this.b = color1.b + color2.b;
		return this;
	},
	addScalar: function ( s ) {
		this.r += s;
		this.g += s;
		this.b += s;
		return this;
	},
	multiply: function ( color ) {
		this.r *= color.r;
		this.g *= color.g;
		this.b *= color.b;
		return this;
	},
	multiplyScalar: function ( s ) {
		this.r *= s;
		this.g *= s;
		this.b *= s;
		return this;
	},
	lerp: function ( color, alpha ) {
		this.r += ( color.r - this.r ) * alpha;
		this.g += ( color.g - this.g ) * alpha;
		this.b += ( color.b - this.b ) * alpha;
		return this;
	},
	equals: function ( c ) {
		return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
	},
	clone: function () {
		return new THREE.Color().setRGB( this.r, this.g, this.b );
	}
};
THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF,
"beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2,
"brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50,
"cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B,
"darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B,
"darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F,
"darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3,
"deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222,
"floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700,
"goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4,
"indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00,
"lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3,
"lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA,
"lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32,
"linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3,
"mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC,
"mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD,
"navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6,
"palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9,
"peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F,
"royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE,
"sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA,
"springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0,
"violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 };
THREE.Quaternion = function ( x, y, z, w ) {
	this._x = x || 0;
	this._y = y || 0;
	this._z = z || 0;
	this._w = ( w !== undefined ) ? w : 1;
};
THREE.Quaternion.prototype = {
	constructor: THREE.Quaternion,
	_x: 0,_y: 0, _z: 0, _w: 0,
	_euler: undefined,
	_updateEuler: function ( callback ) {
		if ( this._euler !== undefined ) {
			this._euler.setFromQuaternion( this, undefined, false );
		}
	},
	get x () {
		return this._x;
	},
	set x ( value ) {
		this._x = value;
		this._updateEuler();
	},
	get y () {
		return this._y;
	},
	set y ( value ) {
		this._y = value;
		this._updateEuler();
	},
	get z () {
		return this._z;
	},
	set z ( value ) {
		this._z = value;
		this._updateEuler();
	},
	get w () {
		return this._w;
	},
	set w ( value ) {
		this._w = value;
		this._updateEuler();
	},
	set: function ( x, y, z, w ) {
		this._x = x;
		this._y = y;
		this._z = z;
		this._w = w;
		this._updateEuler();
		return this;
	},
	copy: function ( quaternion ) {
		this._x = quaternion._x;
		this._y = quaternion._y;
		this._z = quaternion._z;
		this._w = quaternion._w;
		this._updateEuler();
		return this;
	},
	setFromEuler: function ( euler, update ) {
		if ( typeof euler['order'] === undefined ) {
			console.error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.  Please update your code.' );
		}
								var c1 = Math.cos( euler._x / 2 );
		var c2 = Math.cos( euler._y / 2 );
		var c3 = Math.cos( euler._z / 2 );
		var s1 = Math.sin( euler._x / 2 );
		var s2 = Math.sin( euler._y / 2 );
		var s3 = Math.sin( euler._z / 2 );
		if ( euler.order === undefined || euler.order === 'XYZ' ) {
			this._x = s1 * c2 * c3 + c1 * s2 * s3;
			this._y = c1 * s2 * c3 - s1 * c2 * s3;
			this._z = c1 * c2 * s3 + s1 * s2 * c3;
			this._w = c1 * c2 * c3 - s1 * s2 * s3;
		} else if ( euler.order === 'YXZ' ) {
			this._x = s1 * c2 * c3 + c1 * s2 * s3;
			this._y = c1 * s2 * c3 - s1 * c2 * s3;
			this._z = c1 * c2 * s3 - s1 * s2 * c3;
			this._w = c1 * c2 * c3 + s1 * s2 * s3;
		} else if ( euler.order === 'ZXY' ) {
			this._x = s1 * c2 * c3 - c1 * s2 * s3;
			this._y = c1 * s2 * c3 + s1 * c2 * s3;
			this._z = c1 * c2 * s3 + s1 * s2 * c3;
			this._w = c1 * c2 * c3 - s1 * s2 * s3;
		} else if ( euler.order === 'ZYX' ) {
			this._x = s1 * c2 * c3 - c1 * s2 * s3;
			this._y = c1 * s2 * c3 + s1 * c2 * s3;
			this._z = c1 * c2 * s3 - s1 * s2 * c3;
			this._w = c1 * c2 * c3 + s1 * s2 * s3;
		} else if ( euler.order === 'YZX' ) {
			this._x = s1 * c2 * c3 + c1 * s2 * s3;
			this._y = c1 * s2 * c3 + s1 * c2 * s3;
			this._z = c1 * c2 * s3 - s1 * s2 * c3;
			this._w = c1 * c2 * c3 - s1 * s2 * s3;
		} else if ( euler.order === 'XZY' ) {
			this._x = s1 * c2 * c3 - c1 * s2 * s3;
			this._y = c1 * s2 * c3 - s1 * c2 * s3;
			this._z = c1 * c2 * s3 + s1 * s2 * c3;
			this._w = c1 * c2 * c3 + s1 * s2 * s3;
		}
		if ( update !== false ) this._updateEuler();
		return this;
	},
	setFromAxisAngle: function ( axis, angle ) {
						var halfAngle = angle / 2, s = Math.sin( halfAngle );
		this._x = axis.x * s;
		this._y = axis.y * s;
		this._z = axis.z * s;
		this._w = Math.cos( halfAngle );
		this._updateEuler();
		return this;
	},
	setFromRotationMatrix: function ( m ) {
						var te = m.elements,
			m11 = te[0], m12 = te[4], m13 = te[8],
			m21 = te[1], m22 = te[5], m23 = te[9],
			m31 = te[2], m32 = te[6], m33 = te[10],
			trace = m11 + m22 + m33,
			s;
		if ( trace > 0 ) {
			s = 0.5 / Math.sqrt( trace + 1.0 );
			this._w = 0.25 / s;
			this._x = ( m32 - m23 ) * s;
			this._y = ( m13 - m31 ) * s;
			this._z = ( m21 - m12 ) * s;
		} else if ( m11 > m22 && m11 > m33 ) {
			s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
			this._w = (m32 - m23 ) / s;
			this._x = 0.25 * s;
			this._y = (m12 + m21 ) / s;
			this._z = (m13 + m31 ) / s;
		} else if ( m22 > m33 ) {
			s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
			this._w = (m13 - m31 ) / s;
			this._x = (m12 + m21 ) / s;
			this._y = 0.25 * s;
			this._z = (m23 + m32 ) / s;
		} else {
			s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
			this._w = ( m21 - m12 ) / s;
			this._x = ( m13 + m31 ) / s;
			this._y = ( m23 + m32 ) / s;
			this._z = 0.25 * s;
		}
		this._updateEuler();
		return this;
	},
	inverse: function () {
		this.conjugate().normalize();
		return this;
	},
	conjugate: function () {
		this._x *= -1;
		this._y *= -1;
		this._z *= -1;
		this._updateEuler();
		return this;
	},
	lengthSq: function () {
		return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
	},
	length: function () {
		return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
	},
	normalize: function () {
		var l = this.length();
		if ( l === 0 ) {
			this._x = 0;
			this._y = 0;
			this._z = 0;
			this._w = 1;
		} else {
			l = 1 / l;
			this._x = this._x * l;
			this._y = this._y * l;
			this._z = this._z * l;
			this._w = this._w * l;
		}
		return this;
	},
	multiply: function ( q, p ) {
		if ( p !== undefined ) {
			console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
			return this.multiplyQuaternions( q, p );
		}
		return this.multiplyQuaternions( this, q );
	},
	multiplyQuaternions: function ( a, b ) {
				var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
		var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
		this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
		this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
		this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
		this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
		this._updateEuler();
		return this;
	},
	multiplyVector3: function ( vector ) {
		console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
		return vector.applyQuaternion( this );
	},
	slerp: function ( qb, t ) {
		var x = this._x, y = this._y, z = this._z, w = this._w;
				var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
		if ( cosHalfTheta < 0 ) {
			this._w = -qb._w;
			this._x = -qb._x;
			this._y = -qb._y;
			this._z = -qb._z;
			cosHalfTheta = -cosHalfTheta;
		} else {
			this.copy( qb );
		}
		if ( cosHalfTheta >= 1.0 ) {
			this._w = w;
			this._x = x;
			this._y = y;
			this._z = z;
			return this;
		}
		var halfTheta = Math.acos( cosHalfTheta );
		var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
		if ( Math.abs( sinHalfTheta ) < 0.001 ) {
			this._w = 0.5 * ( w + this._w );
			this._x = 0.5 * ( x + this._x );
			this._y = 0.5 * ( y + this._y );
			this._z = 0.5 * ( z + this._z );
			return this;
		}
		var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
		ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
		this._w = ( w * ratioA + this._w * ratioB );
		this._x = ( x * ratioA + this._x * ratioB );
		this._y = ( y * ratioA + this._y * ratioB );
		this._z = ( z * ratioA + this._z * ratioB );
		this._updateEuler();
		return this;
	},
	equals: function ( quaternion ) {
		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
	},
	fromArray: function ( array ) {
		this._x = array[ 0 ];
		this._y = array[ 1 ];
		this._z = array[ 2 ];
		this._w = array[ 3 ];
		this._updateEuler();
		return this;
	},
	toArray: function () {
		return [ this._x, this._y, this._z, this._w ];
	},
	clone: function () {
		return new THREE.Quaternion( this._x, this._y, this._z, this._w );
	}
};
THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
	return qm.copy( qa ).slerp( qb, t );
}
THREE.Vector2 = function ( x, y ) {
	this.x = x || 0;
	this.y = y || 0;
};
THREE.Vector2.prototype = {
	constructor: THREE.Vector2,
	set: function ( x, y ) {
		this.x = x;
		this.y = y;
		return this;
	},
	setX: function ( x ) {
		this.x = x;
		return this;
	},
	setY: function ( y ) {
		this.y = y;
		return this;
	},
	setComponent: function ( index, value ) {
		switch ( index ) {
			case 0: this.x = value; break;
			case 1: this.y = value; break;
			default: throw new Error( "index is out of range: " + index );
		}
	},
	getComponent: function ( index ) {
		switch ( index ) {
			case 0: return this.x;
			case 1: return this.y;
			default: throw new Error( "index is out of range: " + index );
		}
	},
	copy: function ( v ) {
		this.x = v.x;
		this.y = v.y;
		return this;
	},
	add: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
			return this.addVectors( v, w );
		}
		this.x += v.x;
		this.y += v.y;
		return this;
	},
	addVectors: function ( a, b ) {
		this.x = a.x + b.x;
		this.y = a.y + b.y;
		return this;
	},
	addScalar: function ( s ) {
		this.x += s;
		this.y += s;
		return this;
	},
	sub: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
			return this.subVectors( v, w );
		}
		this.x -= v.x;
		this.y -= v.y;
		return this;
	},
	subVectors: function ( a, b ) {
		this.x = a.x - b.x;
		this.y = a.y - b.y;
		return this;
	},
	multiplyScalar: function ( s ) {
		this.x *= s;
		this.y *= s;
		return this;
	},
	divideScalar: function ( scalar ) {
		if ( scalar !== 0 ) {
			var invScalar = 1 / scalar;
			this.x *= invScalar;
			this.y *= invScalar;
		} else {
			this.x = 0;
			this.y = 0;
		}
		return this;
	},
	min: function ( v ) {
		if ( this.x > v.x ) {
			this.x = v.x;
		}
		if ( this.y > v.y ) {
			this.y = v.y;
		}
		return this;
	},
	max: function ( v ) {
		if ( this.x < v.x ) {
			this.x = v.x;
		}
		if ( this.y < v.y ) {
			this.y = v.y;
		}
		return this;
	},
	clamp: function ( min, max ) {
				if ( this.x < min.x ) {
			this.x = min.x;
		} else if ( this.x > max.x ) {
			this.x = max.x;
		}
		if ( this.y < min.y ) {
			this.y = min.y;
		} else if ( this.y > max.y ) {
			this.y = max.y;
		}
		return this;
	},
	negate: function() {
		return this.multiplyScalar( - 1 );
	},
	dot: function ( v ) {
		return this.x * v.x + this.y * v.y;
	},
	lengthSq: function () {
		return this.x * this.x + this.y * this.y;
	},
	length: function () {
		return Math.sqrt( this.x * this.x + this.y * this.y );
	},
	normalize: function () {
		return this.divideScalar( this.length() );
	},
	distanceTo: function ( v ) {
		return Math.sqrt( this.distanceToSquared( v ) );
	},
	distanceToSquared: function ( v ) {
		var dx = this.x - v.x, dy = this.y - v.y;
		return dx * dx + dy * dy;
	},
	setLength: function ( l ) {
		var oldLength = this.length();
		if ( oldLength !== 0 && l !== oldLength ) {
			this.multiplyScalar( l / oldLength );
		}
		return this;
	},
	lerp: function ( v, alpha ) {
		this.x += ( v.x - this.x ) * alpha;
		this.y += ( v.y - this.y ) * alpha;
		return this;
	},
	equals: function( v ) {
		return ( ( v.x === this.x ) && ( v.y === this.y ) );
	},
	fromArray: function ( array ) {
		this.x = array[ 0 ];
		this.y = array[ 1 ];
		return this;
	},
	toArray: function () {
		return [ this.x, this.y ];
	},
	clone: function () {
		return new THREE.Vector2( this.x, this.y );
	}
};
THREE.Vector3 = function ( x, y, z ) {
	this.x = x || 0;
	this.y = y || 0;
	this.z = z || 0;
};
THREE.Vector3.prototype = {
	constructor: THREE.Vector3,
	set: function ( x, y, z ) {
		this.x = x;
		this.y = y;
		this.z = z;
		return this;
	},
	setX: function ( x ) {
		this.x = x;
		return this;
	},
	setY: function ( y ) {
		this.y = y;
		return this;
	},
	setZ: function ( z ) {
		this.z = z;
		return this;
	},
	setComponent: function ( index, value ) {
		switch ( index ) {
			case 0: this.x = value; break;
			case 1: this.y = value; break;
			case 2: this.z = value; break;
			default: throw new Error( "index is out of range: " + index );
		}
	},
	getComponent: function ( index ) {
		switch ( index ) {
			case 0: return this.x;
			case 1: return this.y;
			case 2: return this.z;
			default: throw new Error( "index is out of range: " + index );
		}
	},
	copy: function ( v ) {
		this.x = v.x;
		this.y = v.y;
		this.z = v.z;
		return this;
	},
	add: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
			return this.addVectors( v, w );
		}
		this.x += v.x;
		this.y += v.y;
		this.z += v.z;
		return this;
	},
	addScalar: function ( s ) {
		this.x += s;
		this.y += s;
		this.z += s;
		return this;
	},
	addVectors: function ( a, b ) {
		this.x = a.x + b.x;
		this.y = a.y + b.y;
		this.z = a.z + b.z;
		return this;
	},
	sub: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
			return this.subVectors( v, w );
		}
		this.x -= v.x;
		this.y -= v.y;
		this.z -= v.z;
		return this;
	},
	subVectors: function ( a, b ) {
		this.x = a.x - b.x;
		this.y = a.y - b.y;
		this.z = a.z - b.z;
		return this;
	},
	multiply: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
			return this.multiplyVectors( v, w );
		}
		this.x *= v.x;
		this.y *= v.y;
		this.z *= v.z;
		return this;
	},
	multiplyScalar: function ( scalar ) {
		this.x *= scalar;
		this.y *= scalar;
		this.z *= scalar;
		return this;
	},
	multiplyVectors: function ( a, b ) {
		this.x = a.x * b.x;
		this.y = a.y * b.y;
		this.z = a.z * b.z;
		return this;
	},
	applyMatrix3: function ( m ) {
		var x = this.x;
		var y = this.y;
		var z = this.z;
		var e = m.elements;
		this.x = e[0] * x + e[3] * y + e[6] * z;
		this.y = e[1] * x + e[4] * y + e[7] * z;
		this.z = e[2] * x + e[5] * y + e[8] * z;
		return this;
	},
	applyMatrix4: function ( m ) {
				var x = this.x, y = this.y, z = this.z;
		var e = m.elements;
		this.x = e[0] * x + e[4] * y + e[8]  * z + e[12];
		this.y = e[1] * x + e[5] * y + e[9]  * z + e[13];
		this.z = e[2] * x + e[6] * y + e[10] * z + e[14];
		return this;
	},
	applyProjection: function ( m ) {
				var x = this.x, y = this.y, z = this.z;
		var e = m.elements;
		var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); 		this.x = ( e[0] * x + e[4] * y + e[8]  * z + e[12] ) * d;
		this.y = ( e[1] * x + e[5] * y + e[9]  * z + e[13] ) * d;
		this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d;
		return this;
	},
	applyQuaternion: function ( q ) {
		var x = this.x;
		var y = this.y;
		var z = this.z;
		var qx = q.x;
		var qy = q.y;
		var qz = q.z;
		var qw = q.w;
				var ix =  qw * x + qy * z - qz * y;
		var iy =  qw * y + qz * x - qx * z;
		var iz =  qw * z + qx * y - qy * x;
		var iw = -qx * x - qy * y - qz * z;
				this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
		this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
		this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
		return this;
	},
	transformDirection: function ( m ) {
						var x = this.x, y = this.y, z = this.z;
		var e = m.elements;
		this.x = e[0] * x + e[4] * y + e[8]  * z;
		this.y = e[1] * x + e[5] * y + e[9]  * z;
		this.z = e[2] * x + e[6] * y + e[10] * z;
		this.normalize();
		return this;
	},
	divide: function ( v ) {
		this.x /= v.x;
		this.y /= v.y;
		this.z /= v.z;
		return this;
	},
	divideScalar: function ( scalar ) {
		if ( scalar !== 0 ) {
			var invScalar = 1 / scalar;
			this.x *= invScalar;
			this.y *= invScalar;
			this.z *= invScalar;
		} else {
			this.x = 0;
			this.y = 0;
			this.z = 0;
		}
		return this;
	},
	min: function ( v ) {
		if ( this.x > v.x ) {
			this.x = v.x;
		}
		if ( this.y > v.y ) {
			this.y = v.y;
		}
		if ( this.z > v.z ) {
			this.z = v.z;
		}
		return this;
	},
	max: function ( v ) {
		if ( this.x < v.x ) {
			this.x = v.x;
		}
		if ( this.y < v.y ) {
			this.y = v.y;
		}
		if ( this.z < v.z ) {
			this.z = v.z;
		}
		return this;
	},
	clamp: function ( min, max ) {
				if ( this.x < min.x ) {
			this.x = min.x;
		} else if ( this.x > max.x ) {
			this.x = max.x;
		}
		if ( this.y < min.y ) {
			this.y = min.y;
		} else if ( this.y > max.y ) {
			this.y = max.y;
		}
		if ( this.z < min.z ) {
			this.z = min.z;
		} else if ( this.z > max.z ) {
			this.z = max.z;
		}
		return this;
	},
	negate: function () {
		return this.multiplyScalar( - 1 );
	},
	dot: function ( v ) {
		return this.x * v.x + this.y * v.y + this.z * v.z;
	},
	lengthSq: function () {
		return this.x * this.x + this.y * this.y + this.z * this.z;
	},
	length: function () {
		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
	},
	lengthManhattan: function () {
		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
	},
	normalize: function () {
		return this.divideScalar( this.length() );
	},
	setLength: function ( l ) {
		var oldLength = this.length();
		if ( oldLength !== 0 && l !== oldLength  ) {
			this.multiplyScalar( l / oldLength );
		}
		return this;
	},
	lerp: function ( v, alpha ) {
		this.x += ( v.x - this.x ) * alpha;
		this.y += ( v.y - this.y ) * alpha;
		this.z += ( v.z - this.z ) * alpha;
		return this;
	},
	cross: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
			return this.crossVectors( v, w );
		}
		var x = this.x, y = this.y, z = this.z;
		this.x = y * v.z - z * v.y;
		this.y = z * v.x - x * v.z;
		this.z = x * v.y - y * v.x;
		return this;
	},
	crossVectors: function ( a, b ) {
		this.x = a.y * b.z - a.z * b.y;
		this.y = a.z * b.x - a.x * b.z;
		this.z = a.x * b.y - a.y * b.x;
		return this;
	},
	angleTo: function ( v ) {
		var theta = this.dot( v ) / ( this.length() * v.length() );
				return Math.acos( THREE.Math.clamp( theta, -1, 1 ) );
	},
	distanceTo: function ( v ) {
		return Math.sqrt( this.distanceToSquared( v ) );
	},
	distanceToSquared: function ( v ) {
		var dx = this.x - v.x;
		var dy = this.y - v.y;
		var dz = this.z - v.z;
		return dx * dx + dy * dy + dz * dz;
	},
	setEulerFromRotationMatrix: function ( m, order ) {
		console.error( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code.");
	},
	setEulerFromQuaternion: function ( q, order ) {
		console.error( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code.");
	},
	getPositionFromMatrix: function ( m ) {
		this.x = m.elements[12];
		this.y = m.elements[13];
		this.z = m.elements[14];
		return this;
	},
	getScaleFromMatrix: function ( m ) {
		var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length();
		var sy = this.set( m.elements[4], m.elements[5], m.elements[6] ).length();
		var sz = this.set( m.elements[8], m.elements[9], m.elements[10] ).length();
		this.x = sx;
		this.y = sy;
		this.z = sz;
		return this;
	},
	getColumnFromMatrix: function ( index, matrix ) {
		var offset = index * 4;
		var me = matrix.elements;
		this.x = me[ offset ];
		this.y = me[ offset + 1 ];
		this.z = me[ offset + 2 ];
		return this;
	},
	equals: function ( v ) {
		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
	},
	fromArray: function ( array ) {
		this.x = array[ 0 ];
		this.y = array[ 1 ];
		this.z = array[ 2 ];
		return this;
	},
	toArray: function () {
		return [ this.x, this.y, this.z ];
	},
	clone: function () {
		return new THREE.Vector3( this.x, this.y, this.z );
	}
};
THREE.extend( THREE.Vector3.prototype, {
	applyEuler: function () {
		var q1 = new THREE.Quaternion();
		return function ( rotation ) {
			if( typeof rotation['order'] === undefined ) {
				console.error( 'ERROR: Vector3\'s .applyEuler() now expects a Euler rotation rather than a Vector3 and order.  Please update your code.' );
			}
			var quaternion = q1.setFromEuler( rotation );
			this.applyQuaternion( quaternion );
			return this;
		};
	}(),
	applyAxisAngle: function () {
		var q1 = new THREE.Quaternion();
		return function ( axis, angle ) {
			var quaternion = q1.setFromAxisAngle( axis, angle );
			this.applyQuaternion( quaternion );
			return this;
		};
	}(),
	projectOnVector: function () {
		var v1 = new THREE.Vector3();
		return function ( vector ) {
			v1.copy( vector ).normalize();
			var d = this.dot( v1 );
			return this.copy( v1 ).multiplyScalar( d );
		};
	}(),
	projectOnPlane: function () {
		var v1 = new THREE.Vector3();
		return function ( planeNormal ) {
			v1.copy( this ).projectOnVector( planeNormal );
			return this.sub( v1 );
		}
	}(),
	reflect: function () {
		var v1 = new THREE.Vector3();
		return function ( vector ) {
		    v1.copy( this ).projectOnVector( vector ).multiplyScalar( 2 );
		    return this.subVectors( v1, this );
		}
	}()
} );
THREE.Vector4 = function ( x, y, z, w ) {
	this.x = x || 0;
	this.y = y || 0;
	this.z = z || 0;
	this.w = ( w !== undefined ) ? w : 1;
};
THREE.Vector4.prototype = {
	constructor: THREE.Vector4,
	set: function ( x, y, z, w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
		return this;
	},
	setX: function ( x ) {
		this.x = x;
		return this;
	},
	setY: function ( y ) {
		this.y = y;
		return this;
	},
	setZ: function ( z ) {
		this.z = z;
		return this;
	},
	setW: function ( w ) {
		this.w = w;
		return this;
	},
	setComponent: function ( index, value ) {
		switch ( index ) {
			case 0: this.x = value; break;
			case 1: this.y = value; break;
			case 2: this.z = value; break;
			case 3: this.w = value; break;
			default: throw new Error( "index is out of range: " + index );
		}
	},
	getComponent: function ( index ) {
		switch ( index ) {
			case 0: return this.x;
			case 1: return this.y;
			case 2: return this.z;
			case 3: return this.w;
			default: throw new Error( "index is out of range: " + index );
		}
	},
	copy: function ( v ) {
		this.x = v.x;
		this.y = v.y;
		this.z = v.z;
		this.w = ( v.w !== undefined ) ? v.w : 1;
		return this;
	},
	add: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
			return this.addVectors( v, w );
		}
		this.x += v.x;
		this.y += v.y;
		this.z += v.z;
		this.w += v.w;
		return this;
	},
	addScalar: function ( s ) {
		this.x += s;
		this.y += s;
		this.z += s;
		this.w += s;
		return this;
	},
	addVectors: function ( a, b ) {
		this.x = a.x + b.x;
		this.y = a.y + b.y;
		this.z = a.z + b.z;
		this.w = a.w + b.w;
		return this;
	},
	sub: function ( v, w ) {
		if ( w !== undefined ) {
			console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
			return this.subVectors( v, w );
		}
		this.x -= v.x;
		this.y -= v.y;
		this.z -= v.z;
		this.w -= v.w;
		return this;
	},
	subVectors: function ( a, b ) {
		this.x = a.x - b.x;
		this.y = a.y - b.y;
		this.z = a.z - b.z;
		this.w = a.w - b.w;
		return this;
	},
	multiplyScalar: function ( scalar ) {
		this.x *= scalar;
		this.y *= scalar;
		this.z *= scalar;
		this.w *= scalar;
		return this;
	},
	applyMatrix4: function ( m ) {
		var x = this.x;
		var y = this.y;
		var z = this.z;
		var w = this.w;
		var e = m.elements;
		this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w;
		this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w;
		this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w;
		this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w;
		return this;
	},
	divideScalar: function ( scalar ) {
		if ( scalar !== 0 ) {
			var invScalar = 1 / scalar;
			this.x *= invScalar;
			this.y *= invScalar;
			this.z *= invScalar;
			this.w *= invScalar;
		} else {
			this.x = 0;
			this.y = 0;
			this.z = 0;
			this.w = 1;
		}
		return this;
	},
	setAxisAngleFromQuaternion: function ( q ) {
						this.w = 2 * Math.acos( q.w );
		var s = Math.sqrt( 1 - q.w * q.w );
		if ( s < 0.0001 ) {
			 this.x = 1;
			 this.y = 0;
			 this.z = 0;
		} else {
			 this.x = q.x / s;
			 this.y = q.y / s;
			 this.z = q.z / s;
		}
		return this;
	},
	setAxisAngleFromRotationMatrix: function ( m ) {
						var angle, x, y, z,					epsilon = 0.01,					epsilon2 = 0.1,					te = m.elements,
			m11 = te[0], m12 = te[4], m13 = te[8],
			m21 = te[1], m22 = te[5], m23 = te[9],
			m31 = te[2], m32 = te[6], m33 = te[10];
		if ( ( Math.abs( m12 - m21 ) < epsilon )
		  && ( Math.abs( m13 - m31 ) < epsilon )
		  && ( Math.abs( m23 - m32 ) < epsilon ) ) {
												if ( ( Math.abs( m12 + m21 ) < epsilon2 )
			  && ( Math.abs( m13 + m31 ) < epsilon2 )
			  && ( Math.abs( m23 + m32 ) < epsilon2 )
			  && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
								this.set( 1, 0, 0, 0 );
				return this; 			}
						angle = Math.PI;
			var xx = ( m11 + 1 ) / 2;
			var yy = ( m22 + 1 ) / 2;
			var zz = ( m33 + 1 ) / 2;
			var xy = ( m12 + m21 ) / 4;
			var xz = ( m13 + m31 ) / 4;
			var yz = ( m23 + m32 ) / 4;
			if ( ( xx > yy ) && ( xx > zz ) ) { 				if ( xx < epsilon ) {
					x = 0;
					y = 0.707106781;
					z = 0.707106781;
				} else {
					x = Math.sqrt( xx );
					y = xy / x;
					z = xz / x;
				}
			} else if ( yy > zz ) { 				if ( yy < epsilon ) {
					x = 0.707106781;
					y = 0;
					z = 0.707106781;
				} else {
					y = Math.sqrt( yy );
					x = xy / y;
					z = yz / y;
				}
			} else { 				if ( zz < epsilon ) {
					x = 0.707106781;
					y = 0.707106781;
					z = 0;
				} else {
					z = Math.sqrt( zz );
					x = xz / z;
					y = yz / z;
				}
			}
			this.set( x, y, z, angle );
			return this; 		}
				var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 )
						 + ( m13 - m31 ) * ( m13 - m31 )
						 + ( m21 - m12 ) * ( m21 - m12 ) ); 		if ( Math.abs( s ) < 0.001 ) s = 1;
						this.x = ( m32 - m23 ) / s;
		this.y = ( m13 - m31 ) / s;
		this.z = ( m21 - m12 ) / s;
		this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
		return this;
	},
	min: function ( v ) {
		if ( this.x > v.x ) {
			this.x = v.x;
		}
		if ( this.y > v.y ) {
			this.y = v.y;
		}
		if ( this.z > v.z ) {
			this.z = v.z;
		}
		if ( this.w > v.w ) {
			this.w = v.w;
		}
		return this;
	},
	max: function ( v ) {
		if ( this.x < v.x ) {
			this.x = v.x;
		}
		if ( this.y < v.y ) {
			this.y = v.y;
		}
		if ( this.z < v.z ) {
			this.z = v.z;
		}
		if ( this.w < v.w ) {
			this.w = v.w;
		}
		return this;
	},
	clamp: function ( min, max ) {
				if ( this.x < min.x ) {
			this.x = min.x;
		} else if ( this.x > max.x ) {
			this.x = max.x;
		}
		if ( this.y < min.y ) {
			this.y = min.y;
		} else if ( this.y > max.y ) {
			this.y = max.y;
		}
		if ( this.z < min.z ) {
			this.z = min.z;
		} else if ( this.z > max.z ) {
			this.z = max.z;
		}
		if ( this.w < min.w ) {
			this.w = min.w;
		} else if ( this.w > max.w ) {
			this.w = max.w;
		}
		return this;
	},
	negate: function() {
		return this.multiplyScalar( -1 );
	},
	dot: function ( v ) {
		return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
	},
	lengthSq: function () {
		return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
	},
	length: function () {
		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
	},
	lengthManhattan: function () {
		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
	},
	normalize: function () {
		return this.divideScalar( this.length() );
	},
	setLength: function ( l ) {
		var oldLength = this.length();
		if ( oldLength !== 0 && l !== oldLength ) {
			this.multiplyScalar( l / oldLength );
		}
		return this;
	},
	lerp: function ( v, alpha ) {
		this.x += ( v.x - this.x ) * alpha;
		this.y += ( v.y - this.y ) * alpha;
		this.z += ( v.z - this.z ) * alpha;
		this.w += ( v.w - this.w ) * alpha;
		return this;
	},
	equals: function ( v ) {
		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
	},
	fromArray: function ( array ) {
		this.x = array[ 0 ];
		this.y = array[ 1 ];
		this.z = array[ 2 ];
		this.w = array[ 3 ];
		return this;
	},
	toArray: function () {
		return [ this.x, this.y, this.z, this.w ];
	},
	clone: function () {
		return new THREE.Vector4( this.x, this.y, this.z, this.w );
	}
};
THREE.Euler = function ( x, y, z, order ) {
	this._x = x || 0;
	this._y = y || 0;
	this._z = z || 0;
	this._order = order || THREE.Euler.DefaultOrder;
};
THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
THREE.Euler.DefaultOrder = 'XYZ';
THREE.Euler.prototype = {
	constructor: THREE.Euler,
	_x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder,
	_quaternion: undefined,
	_updateQuaternion: function () {
		if ( this._quaternion !== undefined ) {
			this._quaternion.setFromEuler( this, false );
		}
	},
	get x () {
		return this._x;
	},
	set x ( value ) {
		this._x = value;
		this._updateQuaternion();
	},
	get y () {
		return this._y;
	},
	set y ( value ) {
		this._y = value;
		this._updateQuaternion();
	},
	get z () {
		return this._z;
	},
	set z ( value ) {
		this._z = value;
		this._updateQuaternion();
	},
	get order () {
		return this._order;
	},
	set order ( value ) {
		this._order = value;
		this._updateQuaternion();
	},
	set: function ( x, y, z, order ) {
		this._x = x;
		this._y = y;
		this._z = z;
		this._order = order || this._order;
		this._updateQuaternion();
		return this;
	},
	copy: function ( euler ) {
		this._x = euler._x;
		this._y = euler._y;
		this._z = euler._z;
		this._order = euler._order;
		this._updateQuaternion();
		return this;
	},
	setFromRotationMatrix: function ( m, order ) {
						function clamp( x ) {
			return Math.min( Math.max( x, -1 ), 1 );
		}
		var te = m.elements;
		var m11 = te[0], m12 = te[4], m13 = te[8];
		var m21 = te[1], m22 = te[5], m23 = te[9];
		var m31 = te[2], m32 = te[6], m33 = te[10];
		order = order || this._order;
		if ( order === 'XYZ' ) {
			this._y = Math.asin( clamp( m13 ) );
			if ( Math.abs( m13 ) < 0.99999 ) {
				this._x = Math.atan2( - m23, m33 );
				this._z = Math.atan2( - m12, m11 );
			} else {
				this._x = Math.atan2( m32, m22 );
				this._z = 0;
			}
		} else if ( order === 'YXZ' ) {
			this._x = Math.asin( - clamp( m23 ) );
			if ( Math.abs( m23 ) < 0.99999 ) {
				this._y = Math.atan2( m13, m33 );
				this._z = Math.atan2( m21, m22 );
			} else {
				this._y = Math.atan2( - m31, m11 );
				this._z = 0;
			}
		} else if ( order === 'ZXY' ) {
			this._x = Math.asin( clamp( m32 ) );
			if ( Math.abs( m32 ) < 0.99999 ) {
				this._y = Math.atan2( - m31, m33 );
				this._z = Math.atan2( - m12, m22 );
			} else {
				this._y = 0;
				this._z = Math.atan2( m21, m11 );
			}
		} else if ( order === 'ZYX' ) {
			this._y = Math.asin( - clamp( m31 ) );
			if ( Math.abs( m31 ) < 0.99999 ) {
				this._x = Math.atan2( m32, m33 );
				this._z = Math.atan2( m21, m11 );
			} else {
				this._x = 0;
				this._z = Math.atan2( - m12, m22 );
			}
		} else if ( order === 'YZX' ) {
			this._z = Math.asin( clamp( m21 ) );
			if ( Math.abs( m21 ) < 0.99999 ) {
				this._x = Math.atan2( - m23, m22 );
				this._y = Math.atan2( - m31, m11 );
			} else {
				this._x = 0;
				this._y = Math.atan2( m13, m33 );
			}
		} else if ( order === 'XZY' ) {
			this._z = Math.asin( - clamp( m12 ) );
			if ( Math.abs( m12 ) < 0.99999 ) {
				this._x = Math.atan2( m32, m22 );
				this._y = Math.atan2( m13, m11 );
			} else {
				this._x = Math.atan2( - m23, m33 );
				this._y = 0;
			}
		} else {
			console.warn( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order )
		}
		this._order = order;
		this._updateQuaternion();
		return this;
	},
	setFromQuaternion: function ( q, order, update ) {
						function clamp( x ) {
			return Math.min( Math.max( x, -1 ), 1 );
		}
				var sqx = q.x * q.x;
		var sqy = q.y * q.y;
		var sqz = q.z * q.z;
		var sqw = q.w * q.w;
		order = order || this._order;
		if ( order === 'XYZ' ) {
			this._x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) );
			this._y = Math.asin(  clamp( 2 * ( q.x * q.z + q.y * q.w ) ) );
			this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) );
		} else if ( order ===  'YXZ' ) {
			this._x = Math.asin(  clamp( 2 * ( q.x * q.w - q.y * q.z ) ) );
			this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) );
			this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) );
		} else if ( order === 'ZXY' ) {
			this._x = Math.asin(  clamp( 2 * ( q.x * q.w + q.y * q.z ) ) );
			this._y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) );
			this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) );
		} else if ( order === 'ZYX' ) {
			this._x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) );
			this._y = Math.asin(  clamp( 2 * ( q.y * q.w - q.x * q.z ) ) );
			this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) );
		} else if ( order === 'YZX' ) {
			this._x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) );
			this._y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) );
			this._z = Math.asin(  clamp( 2 * ( q.x * q.y + q.z * q.w ) ) );
		} else if ( order === 'XZY' ) {
			this._x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) );
			this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) );
			this._z = Math.asin(  clamp( 2 * ( q.z * q.w - q.x * q.y ) ) );
		} else {
			console.warn( 'WARNING: Euler.setFromQuaternion() given unsupported order: ' + order )
		}
		this._order = order;
		if ( update !== false ) this._updateQuaternion();
		return this;
	},
	reorder: function () {
				var q = new THREE.Quaternion();
		return function ( newOrder ) {
			q.setFromEuler( this );
			this.setFromQuaternion( q, newOrder );
		};
	}(),
	fromArray: function ( array ) {
		this._x = array[ 0 ];
		this._y = array[ 1 ];
		this._z = array[ 2 ];
		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
		this._updateQuaternion();
		return this;
	},
	toArray: function () {
		return [ this._x, this._y, this._z, this._order ];
	},
	equals: function ( euler ) {
		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
	},
	clone: function () {
		return new THREE.Euler( this._x, this._y, this._z, this._order );
	}
};
THREE.Line3 = function ( start, end ) {
	this.start = ( start !== undefined ) ? start : new THREE.Vector3();
	this.end = ( end !== undefined ) ? end : new THREE.Vector3();
};
THREE.Line3.prototype = {
	constructor: THREE.Line3,
	set: function ( start, end ) {
		this.start.copy( start );
		this.end.copy( end );
		return this;
	},
	copy: function ( line ) {
		this.start.copy( line.start );
		this.end.copy( line.end );
		return this;
	},
	center: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
	},
	delta: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.subVectors( this.end, this.start );
	},
	distanceSq: function () {
		return this.start.distanceToSquared( this.end );
	},
	distance: function () {
		return this.start.distanceTo( this.end );
	},
	at: function ( t, optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return this.delta( result ).multiplyScalar( t ).add( this.start );
	},
	closestPointToPointParameter: function() {
		var startP = new THREE.Vector3();
		var startEnd = new THREE.Vector3();
		return function ( point, clampToLine ) {
			startP.subVectors( point, this.start );
			startEnd.subVectors( this.end, this.start );
			var startEnd2 = startEnd.dot( startEnd );
			var startEnd_startP = startEnd.dot( startP );
			var t = startEnd_startP / startEnd2;
			if ( clampToLine ) {
				t = THREE.Math.clamp( t, 0, 1 );
			}
			return t;
		};
	}(),
	closestPointToPoint: function ( point, clampToLine, optionalTarget ) {
		var t = this.closestPointToPointParameter( point, clampToLine );
		var result = optionalTarget || new THREE.Vector3();
		return this.delta( result ).multiplyScalar( t ).add( this.start );
	},
	applyMatrix4: function ( matrix ) {
		this.start.applyMatrix4( matrix );
		this.end.applyMatrix4( matrix );
		return this;
	},
	equals: function ( line ) {
		return line.start.equals( this.start ) && line.end.equals( this.end );
	},
	clone: function () {
		return new THREE.Line3().copy( this );
	}
};
THREE.Box2 = function ( min, max ) {
	this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity );
	this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity );
};
THREE.Box2.prototype = {
	constructor: THREE.Box2,
	set: function ( min, max ) {
		this.min.copy( min );
		this.max.copy( max );
		return this;
	},
	setFromPoints: function ( points ) {
		if ( points.length > 0 ) {
			var point = points[ 0 ];
			this.min.copy( point );
			this.max.copy( point );
			for ( var i = 1, il = points.length; i < il; i ++ ) {
				point = points[ i ];
				if ( point.x < this.min.x ) {
					this.min.x = point.x;
				} else if ( point.x > this.max.x ) {
					this.max.x = point.x;
				}
				if ( point.y < this.min.y ) {
					this.min.y = point.y;
				} else if ( point.y > this.max.y ) {
					this.max.y = point.y;
				}
			}
		} else {
			this.makeEmpty();
		}
		return this;
	},
	setFromCenterAndSize: function () {
		var v1 = new THREE.Vector2();
		return function ( center, size ) {
			var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
			this.min.copy( center ).sub( halfSize );
			this.max.copy( center ).add( halfSize );
			return this;
		};
	}(),
	copy: function ( box ) {
		this.min.copy( box.min );
		this.max.copy( box.max );
		return this;
	},
	makeEmpty: function () {
		this.min.x = this.min.y = Infinity;
		this.max.x = this.max.y = -Infinity;
		return this;
	},
	empty: function () {
				return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
	},
	center: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector2();
		return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
	},
	size: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector2();
		return result.subVectors( this.max, this.min );
	},
	expandByPoint: function ( point ) {
		this.min.min( point );
		this.max.max( point );
		return this;
	},
	expandByVector: function ( vector ) {
		this.min.sub( vector );
		this.max.add( vector );
		return this;
	},
	expandByScalar: function ( scalar ) {
		this.min.addScalar( -scalar );
		this.max.addScalar( scalar );
		return this;
	},
	containsPoint: function ( point ) {
		if ( point.x < this.min.x || point.x > this.max.x ||
		     point.y < this.min.y || point.y > this.max.y ) {
			return false;
		}
		return true;
	},
	containsBox: function ( box ) {
		if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&
		     ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) {
			return true;
		}
		return false;
	},
	getParameter: function ( point ) {
						return new THREE.Vector2(
			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
			( point.y - this.min.y ) / ( this.max.y - this.min.y )
		);
	},
	isIntersectionBox: function ( box ) {
				if ( box.max.x < this.min.x || box.min.x > this.max.x ||
		     box.max.y < this.min.y || box.min.y > this.max.y ) {
			return false;
		}
		return true;
	},
	clampPoint: function ( point, optionalTarget ) {
		var result = optionalTarget || new THREE.Vector2();
		return result.copy( point ).clamp( this.min, this.max );
	},
	distanceToPoint: function () {
		var v1 = new THREE.Vector2();
		return function ( point ) {
			var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
			return clampedPoint.sub( point ).length();
		};
	}(),
	intersect: function ( box ) {
		this.min.max( box.min );
		this.max.min( box.max );
		return this;
	},
	union: function ( box ) {
		this.min.min( box.min );
		this.max.max( box.max );
		return this;
	},
	translate: function ( offset ) {
		this.min.add( offset );
		this.max.add( offset );
		return this;
	},
	equals: function ( box ) {
		return box.min.equals( this.min ) && box.max.equals( this.max );
	},
	clone: function () {
		return new THREE.Box2().copy( this );
	}
};
THREE.Box3 = function ( min, max ) {
	this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity );
	this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity );
};
THREE.Box3.prototype = {
	constructor: THREE.Box3,
	set: function ( min, max ) {
		this.min.copy( min );
		this.max.copy( max );
		return this;
	},
	setFromPoints: function ( points ) {
		if ( points.length > 0 ) {
			var point = points[ 0 ];
			this.min.copy( point );
			this.max.copy( point );
			for ( var i = 1, il = points.length; i < il; i ++ ) {
				point = points[ i ];
				if ( point.x < this.min.x ) {
					this.min.x = point.x;
				} else if ( point.x > this.max.x ) {
					this.max.x = point.x;
				}
				if ( point.y < this.min.y ) {
					this.min.y = point.y;
				} else if ( point.y > this.max.y ) {
					this.max.y = point.y;
				}
				if ( point.z < this.min.z ) {
					this.min.z = point.z;
				} else if ( point.z > this.max.z ) {
					this.max.z = point.z;
				}
			}
		} else {
			this.makeEmpty();
		}
		return this;
	},
	setFromCenterAndSize: function() {
		var v1 = new THREE.Vector3();
		return function ( center, size ) {
			var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
			this.min.copy( center ).sub( halfSize );
			this.max.copy( center ).add( halfSize );
			return this;
		};
	}(),
	setFromObject: function() {
						var v1 = new THREE.Vector3();
		return function( object ) {
			var scope = this;
			object.updateMatrixWorld( true );
			this.makeEmpty();
			object.traverse( function ( node ) {
				if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) {
					var vertices = node.geometry.vertices;
					for ( var i = 0, il = vertices.length; i < il; i++ ) {
						v1.copy( vertices[ i ] );
						v1.applyMatrix4( node.matrixWorld );
						scope.expandByPoint( v1 );
					}
				}
			} );
			return this;
		};
	}(),
	copy: function ( box ) {
		this.min.copy( box.min );
		this.max.copy( box.max );
		return this;
	},
	makeEmpty: function () {
		this.min.x = this.min.y = this.min.z = Infinity;
		this.max.x = this.max.y = this.max.z = -Infinity;
		return this;
	},
	empty: function () {
				return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
	},
	center: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
	},
	size: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.subVectors( this.max, this.min );
	},
	expandByPoint: function ( point ) {
		this.min.min( point );
		this.max.max( point );
		return this;
	},
	expandByVector: function ( vector ) {
		this.min.sub( vector );
		this.max.add( vector );
		return this;
	},
	expandByScalar: function ( scalar ) {
		this.min.addScalar( -scalar );
		this.max.addScalar( scalar );
		return this;
	},
	containsPoint: function ( point ) {
		if ( point.x < this.min.x || point.x > this.max.x ||
		     point.y < this.min.y || point.y > this.max.y ||
		     point.z < this.min.z || point.z > this.max.z ) {
			return false;
		}
		return true;
	},
	containsBox: function ( box ) {
		if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&
			 ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) &&
			 ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) {
			return true;
		}
		return false;
	},
	getParameter: function ( point ) {
						return new THREE.Vector3(
			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
			( point.y - this.min.y ) / ( this.max.y - this.min.y ),
			( point.z - this.min.z ) / ( this.max.z - this.min.z )
		);
	},
	isIntersectionBox: function ( box ) {
				if ( box.max.x < this.min.x || box.min.x > this.max.x ||
		     box.max.y < this.min.y || box.min.y > this.max.y ||
		     box.max.z < this.min.z || box.min.z > this.max.z ) {
			return false;
		}
		return true;
	},
	clampPoint: function ( point, optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.copy( point ).clamp( this.min, this.max );
	},
	distanceToPoint: function() {
		var v1 = new THREE.Vector3();
		return function ( point ) {
			var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
			return clampedPoint.sub( point ).length();
		};
	}(),
	getBoundingSphere: function() {
		var v1 = new THREE.Vector3();
		return function ( optionalTarget ) {
			var result = optionalTarget || new THREE.Sphere();
			result.center = this.center();
			result.radius = this.size( v1 ).length() * 0.5;
			return result;
		};
	}(),
	intersect: function ( box ) {
		this.min.max( box.min );
		this.max.min( box.max );
		return this;
	},
	union: function ( box ) {
		this.min.min( box.min );
		this.max.max( box.max );
		return this;
	},
	applyMatrix4: function() {
		var points = [
			new THREE.Vector3(),
			new THREE.Vector3(),
			new THREE.Vector3(),
			new THREE.Vector3(),
			new THREE.Vector3(),
			new THREE.Vector3(),
			new THREE.Vector3(),
			new THREE.Vector3()
		];
		return function ( matrix ) {
						points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); 			points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); 			points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); 			points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); 			points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); 			points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); 			points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); 			points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix );  			this.makeEmpty();
			this.setFromPoints( points );
			return this;
		};
	}(),
	translate: function ( offset ) {
		this.min.add( offset );
		this.max.add( offset );
		return this;
	},
	equals: function ( box ) {
		return box.min.equals( this.min ) && box.max.equals( this.max );
	},
	clone: function () {
		return new THREE.Box3().copy( this );
	}
};
THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
	this.elements = new Float32Array(9);
	this.set(
		( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0,
		n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0,
		n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1
	);
};
THREE.Matrix3.prototype = {
	constructor: THREE.Matrix3,
	set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
		var te = this.elements;
		te[0] = n11; te[3] = n12; te[6] = n13;
		te[1] = n21; te[4] = n22; te[7] = n23;
		te[2] = n31; te[5] = n32; te[8] = n33;
		return this;
	},
	identity: function () {
		this.set(
			1, 0, 0,
			0, 1, 0,
			0, 0, 1
		);
		return this;
	},
	copy: function ( m ) {
		var me = m.elements;
		this.set(
			me[0], me[3], me[6],
			me[1], me[4], me[7],
			me[2], me[5], me[8]
		);
		return this;
	},
	multiplyVector3: function ( vector ) {
		console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
		return vector.applyMatrix3( this );
	},
	multiplyVector3Array: function() {
		var v1 = new THREE.Vector3();
		return function ( a ) {
			for ( var i = 0, il = a.length; i < il; i += 3 ) {
				v1.x = a[ i ];
				v1.y = a[ i + 1 ];
				v1.z = a[ i + 2 ];
				v1.applyMatrix3(this);
				a[ i ]     = v1.x;
				a[ i + 1 ] = v1.y;
				a[ i + 2 ] = v1.z;
			}
			return a;
		};
	}(),
	multiplyScalar: function ( s ) {
		var te = this.elements;
		te[0] *= s; te[3] *= s; te[6] *= s;
		te[1] *= s; te[4] *= s; te[7] *= s;
		te[2] *= s; te[5] *= s; te[8] *= s;
		return this;
	},
	determinant: function () {
		var te = this.elements;
		var a = te[0], b = te[1], c = te[2],
			d = te[3], e = te[4], f = te[5],
			g = te[6], h = te[7], i = te[8];
		return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g;
	},
	getInverse: function ( matrix, throwOnInvertible ) {
						var me = matrix.elements;
		var te = this.elements;
		te[ 0 ] =   me[10] * me[5] - me[6] * me[9];
		te[ 1 ] = - me[10] * me[1] + me[2] * me[9];
		te[ 2 ] =   me[6] * me[1] - me[2] * me[5];
		te[ 3 ] = - me[10] * me[4] + me[6] * me[8];
		te[ 4 ] =   me[10] * me[0] - me[2] * me[8];
		te[ 5 ] = - me[6] * me[0] + me[2] * me[4];
		te[ 6 ] =   me[9] * me[4] - me[5] * me[8];
		te[ 7 ] = - me[9] * me[0] + me[1] * me[8];
		te[ 8 ] =   me[5] * me[0] - me[1] * me[4];
		var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ];
				if ( det === 0 ) {
			var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0";
			if ( throwOnInvertible || false ) {
				throw new Error( msg ); 
			} else {
				console.warn( msg );
			}
			this.identity();
			return this;
		}
		this.multiplyScalar( 1.0 / det );
		return this;
	},
	transpose: function () {
		var tmp, m = this.elements;
		tmp = m[1]; m[1] = m[3]; m[3] = tmp;
		tmp = m[2]; m[2] = m[6]; m[6] = tmp;
		tmp = m[5]; m[5] = m[7]; m[7] = tmp;
		return this;
	},
	getNormalMatrix: function ( m ) {
				this.getInverse( m ).transpose();
		return this;
	},
	transposeIntoArray: function ( r ) {
		var m = this.elements;
		r[ 0 ] = m[ 0 ];
		r[ 1 ] = m[ 3 ];
		r[ 2 ] = m[ 6 ];
		r[ 3 ] = m[ 1 ];
		r[ 4 ] = m[ 4 ];
		r[ 5 ] = m[ 7 ];
		r[ 6 ] = m[ 2 ];
		r[ 7 ] = m[ 5 ];
		r[ 8 ] = m[ 8 ];
		return this;
	},
	clone: function () {
		var te = this.elements;
		return new THREE.Matrix3(
			te[0], te[3], te[6],
			te[1], te[4], te[7],
			te[2], te[5], te[8]
		);
	}
};
THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
	this.elements = new Float32Array( 16 );
			var te = this.elements;
	te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0;
	te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0;
	te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0;
	te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1;
};
THREE.Matrix4.prototype = {
	constructor: THREE.Matrix4,
	set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
		var te = this.elements;
		te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14;
		te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24;
		te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34;
		te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44;
		return this;
	},
	identity: function () {
		this.set(
			1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 1, 0,
			0, 0, 0, 1
		);
		return this;
	},
	copy: function ( m ) {
		this.elements.set( m.elements );
		return this;
	},
	extractPosition: function ( m ) {
		console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' );
		return this.copyPosition( m );
	},
	copyPosition: function ( m ) {
		var te = this.elements;
		var me = m.elements;
		te[12] = me[12];
		te[13] = me[13];
		te[14] = me[14];
		return this;
	},
	extractRotation: function () {
		var v1 = new THREE.Vector3();
		return function ( m ) {
			var te = this.elements;
			var me = m.elements;
			var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length();
			var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length();
			var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length();
			te[0] = me[0] * scaleX;
			te[1] = me[1] * scaleX;
			te[2] = me[2] * scaleX;
			te[4] = me[4] * scaleY;
			te[5] = me[5] * scaleY;
			te[6] = me[6] * scaleY;
			te[8] = me[8] * scaleZ;
			te[9] = me[9] * scaleZ;
			te[10] = me[10] * scaleZ;
			return this;
		};
	}(),
	makeRotationFromEuler: function ( euler ) {
		if ( typeof euler['order'] === undefined ) {
			console.error( 'ERROR: Matrix\'s .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.  Please update your code.' );
		}
		var te = this.elements;
		var x = euler.x, y = euler.y, z = euler.z;
		var a = Math.cos( x ), b = Math.sin( x );
		var c = Math.cos( y ), d = Math.sin( y );
		var e = Math.cos( z ), f = Math.sin( z );
		if ( euler.order === undefined || euler.order === 'XYZ' ) {
			var ae = a * e, af = a * f, be = b * e, bf = b * f;
			te[0] = c * e;
			te[4] = - c * f;
			te[8] = d;
			te[1] = af + be * d;
			te[5] = ae - bf * d;
			te[9] = - b * c;
			te[2] = bf - ae * d;
			te[6] = be + af * d;
			te[10] = a * c;
		} else if ( euler.order === 'YXZ' ) {
			var ce = c * e, cf = c * f, de = d * e, df = d * f;
			te[0] = ce + df * b;
			te[4] = de * b - cf;
			te[8] = a * d;
			te[1] = a * f;
			te[5] = a * e;
			te[9] = - b;
			te[2] = cf * b - de;
			te[6] = df + ce * b;
			te[10] = a * c;
		} else if ( euler.order === 'ZXY' ) {
			var ce = c * e, cf = c * f, de = d * e, df = d * f;
			te[0] = ce - df * b;
			te[4] = - a * f;
			te[8] = de + cf * b;
			te[1] = cf + de * b;
			te[5] = a * e;
			te[9] = df - ce * b;
			te[2] = - a * d;
			te[6] = b;
			te[10] = a * c;
		} else if ( euler.order === 'ZYX' ) {
			var ae = a * e, af = a * f, be = b * e, bf = b * f;
			te[0] = c * e;
			te[4] = be * d - af;
			te[8] = ae * d + bf;
			te[1] = c * f;
			te[5] = bf * d + ae;
			te[9] = af * d - be;
			te[2] = - d;
			te[6] = b * c;
			te[10] = a * c;
		} else if ( euler.order === 'YZX' ) {
			var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
			te[0] = c * e;
			te[4] = bd - ac * f;
			te[8] = bc * f + ad;
			te[1] = f;
			te[5] = a * e;
			te[9] = - b * e;
			te[2] = - d * e;
			te[6] = ad * f + bc;
			te[10] = ac - bd * f;
		} else if ( euler.order === 'XZY' ) {
			var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
			te[0] = c * e;
			te[4] = - f;
			te[8] = d * e;
			te[1] = ac * f + bd;
			te[5] = a * e;
			te[9] = ad * f - bc;
			te[2] = bc * f - ad;
			te[6] = b * e;
			te[10] = bd * f + ac;
		}
				te[3] = 0;
		te[7] = 0;
		te[11] = 0;
				te[12] = 0;
		te[13] = 0;
		te[14] = 0;
		te[15] = 1;
		return this;
	},
	setRotationFromQuaternion: function ( q ) {
		console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion.  Please update your code.' );
		return this.makeRotationFromQuaternion( q );
	},
	makeRotationFromQuaternion: function ( q ) {
		var te = this.elements;
		var x = q.x, y = q.y, z = q.z, w = q.w;
		var x2 = x + x, y2 = y + y, z2 = z + z;
		var xx = x * x2, xy = x * y2, xz = x * z2;
		var yy = y * y2, yz = y * z2, zz = z * z2;
		var wx = w * x2, wy = w * y2, wz = w * z2;
		te[0] = 1 - ( yy + zz );
		te[4] = xy - wz;
		te[8] = xz + wy;
		te[1] = xy + wz;
		te[5] = 1 - ( xx + zz );
		te[9] = yz - wx;
		te[2] = xz - wy;
		te[6] = yz + wx;
		te[10] = 1 - ( xx + yy );
				te[3] = 0;
		te[7] = 0;
		te[11] = 0;
				te[12] = 0;
		te[13] = 0;
		te[14] = 0;
		te[15] = 1;
		return this;
	},
	lookAt: function() {
		var x = new THREE.Vector3();
		var y = new THREE.Vector3();
		var z = new THREE.Vector3();
		return function ( eye, target, up ) {
			var te = this.elements;
			z.subVectors( eye, target ).normalize();
			if ( z.length() === 0 ) {
				z.z = 1;
			}
			x.crossVectors( up, z ).normalize();
			if ( x.length() === 0 ) {
				z.x += 0.0001;
				x.crossVectors( up, z ).normalize();
			}
			y.crossVectors( z, x );
			te[0] = x.x; te[4] = y.x; te[8] = z.x;
			te[1] = x.y; te[5] = y.y; te[9] = z.y;
			te[2] = x.z; te[6] = y.z; te[10] = z.z;
			return this;
		};
	}(),
	multiply: function ( m, n ) {
		if ( n !== undefined ) {
			console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
			return this.multiplyMatrices( m, n );
		}
		return this.multiplyMatrices( this, m );
	},
	multiplyMatrices: function ( a, b ) {
		var ae = a.elements;
		var be = b.elements;
		var te = this.elements;
		var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
		var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
		var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
		var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];
		var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12];
		var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13];
		var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14];
		var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15];
		te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
		te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
		te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
		te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
		te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
		te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
		te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
		te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
		te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
		te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
		te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
		te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
		te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
		te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
		te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
		te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
		return this;
	},
	multiplyToArray: function ( a, b, r ) {
		var te = this.elements;
		this.multiplyMatrices( a, b );
		r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3];
		r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7];
		r[ 8 ]  = te[8]; r[ 9 ]  = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11];
		r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15];
		return this;
	},
	multiplyScalar: function ( s ) {
		var te = this.elements;
		te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s;
		te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s;
		te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s;
		te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s;
		return this;
	},
	multiplyVector3: function ( vector ) {
		console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' );
		return vector.applyProjection( this );
	},
	multiplyVector4: function ( vector ) {
		console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
		return vector.applyMatrix4( this );
	},
	multiplyVector3Array: function() {
		var v1 = new THREE.Vector3();
		return function ( a ) {
			for ( var i = 0, il = a.length; i < il; i += 3 ) {
				v1.x = a[ i ];
				v1.y = a[ i + 1 ];
				v1.z = a[ i + 2 ];
				v1.applyProjection( this );
				a[ i ]     = v1.x;
				a[ i + 1 ] = v1.y;
				a[ i + 2 ] = v1.z;
			}
			return a;
		};
	}(),
	rotateAxis: function ( v ) {
		console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
		v.transformDirection( this );
	},
	crossVector: function ( vector ) {
		console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
		return vector.applyMatrix4( this );
	},
	determinant: function () {
		var te = this.elements;
		var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12];
		var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13];
		var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14];
		var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15];
						return (
			n41 * (
				+n14 * n23 * n32
				-n13 * n24 * n32
				-n14 * n22 * n33
				+n12 * n24 * n33
				+n13 * n22 * n34
				-n12 * n23 * n34
			) +
			n42 * (
				+n11 * n23 * n34
				-n11 * n24 * n33
				+n14 * n21 * n33
				-n13 * n21 * n34
				+n13 * n24 * n31
				-n14 * n23 * n31
			) +
			n43 * (
				+n11 * n24 * n32
				-n11 * n22 * n34
				-n14 * n21 * n32
				+n12 * n21 * n34
				+n14 * n22 * n31
				-n12 * n24 * n31
			) +
			n44 * (
				-n13 * n22 * n31
				-n11 * n23 * n32
				+n11 * n22 * n33
				+n13 * n21 * n32
				-n12 * n21 * n33
				+n12 * n23 * n31
			)
		);
	},
	transpose: function () {
		var te = this.elements;
		var tmp;
		tmp = te[1]; te[1] = te[4]; te[4] = tmp;
		tmp = te[2]; te[2] = te[8]; te[8] = tmp;
		tmp = te[6]; te[6] = te[9]; te[9] = tmp;
		tmp = te[3]; te[3] = te[12]; te[12] = tmp;
		tmp = te[7]; te[7] = te[13]; te[13] = tmp;
		tmp = te[11]; te[11] = te[14]; te[14] = tmp;
		return this;
	},
	flattenToArray: function ( flat ) {
		var te = this.elements;
		flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3];
		flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7];
		flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11];
		flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15];
		return flat;
	},
	flattenToArrayOffset: function( flat, offset ) {
		var te = this.elements;
		flat[ offset ] = te[0];
		flat[ offset + 1 ] = te[1];
		flat[ offset + 2 ] = te[2];
		flat[ offset + 3 ] = te[3];
		flat[ offset + 4 ] = te[4];
		flat[ offset + 5 ] = te[5];
		flat[ offset + 6 ] = te[6];
		flat[ offset + 7 ] = te[7];
		flat[ offset + 8 ]  = te[8];
		flat[ offset + 9 ]  = te[9];
		flat[ offset + 10 ] = te[10];
		flat[ offset + 11 ] = te[11];
		flat[ offset + 12 ] = te[12];
		flat[ offset + 13 ] = te[13];
		flat[ offset + 14 ] = te[14];
		flat[ offset + 15 ] = te[15];
		return flat;
	},
	getPosition: function() {
		var v1 = new THREE.Vector3();
		return function () {
			console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.getPositionFromMatrix( matrix ) instead.' );
			var te = this.elements;
			return v1.set( te[12], te[13], te[14] );
		};
	}(),
	setPosition: function ( v ) {
		var te = this.elements;
		te[12] = v.x;
		te[13] = v.y;
		te[14] = v.z;
		return this;
	},
	getInverse: function ( m, throwOnInvertible ) {
				var te = this.elements;
		var me = m.elements;
		var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12];
		var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13];
		var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14];
		var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15];
		te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44;
		te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44;
		te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44;
		te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34;
		te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44;
		te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44;
		te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44;
		te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34;
		te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44;
		te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44;
		te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44;
		te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34;
		te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43;
		te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43;
		te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43;
		te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33;
		var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ];
		if ( det == 0 ) {
			var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0";
			if ( throwOnInvertible || false ) {
				throw new Error( msg ); 
			} else {
				console.warn( msg );
			}
			this.identity();
			return this;
		}
		this.multiplyScalar( 1 / det );
		return this;
	},
	translate: function ( v ) {
		console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.');
	},
	rotateX: function ( angle ) {
		console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.');
	},
	rotateY: function ( angle ) {
		console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.');
	},
	rotateZ: function ( angle ) {
		console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.');
	},
	rotateByAxis: function ( axis, angle ) {
		console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.');
	},
	scale: function ( v ) {
		var te = this.elements;
		var x = v.x, y = v.y, z = v.z;
		te[0] *= x; te[4] *= y; te[8] *= z;
		te[1] *= x; te[5] *= y; te[9] *= z;
		te[2] *= x; te[6] *= y; te[10] *= z;
		te[3] *= x; te[7] *= y; te[11] *= z;
		return this;
	},
	getMaxScaleOnAxis: function () {
		var te = this.elements;
		var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
		var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
		var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
		return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) );
	},
	makeTranslation: function ( x, y, z ) {
		this.set(
			1, 0, 0, x,
			0, 1, 0, y,
			0, 0, 1, z,
			0, 0, 0, 1
		);
		return this;
	},
	makeRotationX: function ( theta ) {
		var c = Math.cos( theta ), s = Math.sin( theta );
		this.set(
			1, 0,  0, 0,
			0, c, -s, 0,
			0, s,  c, 0,
			0, 0,  0, 1
		);
		return this;
	},
	makeRotationY: function ( theta ) {
		var c = Math.cos( theta ), s = Math.sin( theta );
		this.set(
			 c, 0, s, 0,
			 0, 1, 0, 0,
			-s, 0, c, 0,
			 0, 0, 0, 1
		);
		return this;
	},
	makeRotationZ: function ( theta ) {
		var c = Math.cos( theta ), s = Math.sin( theta );
		this.set(
			c, -s, 0, 0,
			s,  c, 0, 0,
			0,  0, 1, 0,
			0,  0, 0, 1
		);
		return this;
	},
	makeRotationAxis: function ( axis, angle ) {
				var c = Math.cos( angle );
		var s = Math.sin( angle );
		var t = 1 - c;
		var x = axis.x, y = axis.y, z = axis.z;
		var tx = t * x, ty = t * y;
		this.set(
			tx * x + c, tx * y - s * z, tx * z + s * y, 0,
			tx * y + s * z, ty * y + c, ty * z - s * x, 0,
			tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
			0, 0, 0, 1
		);
		 return this;
	},
	makeScale: function ( x, y, z ) {
		this.set(
			x, 0, 0, 0,
			0, y, 0, 0,
			0, 0, z, 0,
			0, 0, 0, 1
		);
		return this;
	},
	compose: function ( position, quaternion, scale ) {
		this.makeRotationFromQuaternion( quaternion );
		this.scale( scale );
		this.setPosition( position );
		return this;
	},
	decompose: function () {
		var vector = new THREE.Vector3();
		var matrix = new THREE.Matrix4();
		return function ( position, quaternion, scale ) {
			var te = this.elements;
			var sx = vector.set( te[0], te[1], te[2] ).length();
			var sy = vector.set( te[4], te[5], te[6] ).length();
			var sz = vector.set( te[8], te[9], te[10] ).length();
			position.x = te[12];
			position.y = te[13];
			position.z = te[14];
						matrix.elements.set( this.elements ); 			var invSX = 1 / sx;
			var invSY = 1 / sy;
			var invSZ = 1 / sz;
			matrix.elements[0] *= invSX;
			matrix.elements[1] *= invSX;
			matrix.elements[2] *= invSX;
			matrix.elements[4] *= invSY;
			matrix.elements[5] *= invSY;
			matrix.elements[6] *= invSY;
			matrix.elements[8] *= invSZ;
			matrix.elements[9] *= invSZ;
			matrix.elements[10] *= invSZ;
			quaternion.setFromRotationMatrix( matrix );
			scale.x = sx;
			scale.y = sy;
			scale.z = sz;
			return this;
		};
	}(),
	makeFrustum: function ( left, right, bottom, top, near, far ) {
		var te = this.elements;
		var x = 2 * near / ( right - left );
		var y = 2 * near / ( top - bottom );
		var a = ( right + left ) / ( right - left );
		var b = ( top + bottom ) / ( top - bottom );
		var c = - ( far + near ) / ( far - near );
		var d = - 2 * far * near / ( far - near );
		te[0] = x;	te[4] = 0;	te[8] = a;	te[12] = 0;
		te[1] = 0;	te[5] = y;	te[9] = b;	te[13] = 0;
		te[2] = 0;	te[6] = 0;	te[10] = c;	te[14] = d;
		te[3] = 0;	te[7] = 0;	te[11] = - 1;	te[15] = 0;
		return this;
	},
	makePerspective: function ( fov, aspect, near, far ) {
		var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) );
		var ymin = - ymax;
		var xmin = ymin * aspect;
		var xmax = ymax * aspect;
		return this.makeFrustum( xmin, xmax, ymin, ymax, near, far );
	},
	makeOrthographic: function ( left, right, top, bottom, near, far ) {
		var te = this.elements;
		var w = right - left;
		var h = top - bottom;
		var p = far - near;
		var x = ( right + left ) / w;
		var y = ( top + bottom ) / h;
		var z = ( far + near ) / p;
		te[0] = 2 / w;	te[4] = 0;	te[8] = 0;	te[12] = -x;
		te[1] = 0;	te[5] = 2 / h;	te[9] = 0;	te[13] = -y;
		te[2] = 0;	te[6] = 0;	te[10] = -2/p;	te[14] = -z;
		te[3] = 0;	te[7] = 0;	te[11] = 0;	te[15] = 1;
		return this;
	},
	fromArray: function ( array ) {
		this.elements.set( array );
		return this;
	},
	toArray: function () {
		var te = this.elements;
		return [
			te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ],
			te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ],
			te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ],
			te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ]
		];
	},
	clone: function () {
		var te = this.elements;
		return new THREE.Matrix4(
			te[0], te[4], te[8], te[12],
			te[1], te[5], te[9], te[13],
			te[2], te[6], te[10], te[14],
			te[3], te[7], te[11], te[15]
		);
	}
};
THREE.Ray = function ( origin, direction ) {
	this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();
	this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3();
};
THREE.Ray.prototype = {
	constructor: THREE.Ray,
	set: function ( origin, direction ) {
		this.origin.copy( origin );
		this.direction.copy( direction );
		return this;
	},
	copy: function ( ray ) {
		this.origin.copy( ray.origin );
		this.direction.copy( ray.direction );
		return this;
	},
	at: function ( t, optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
	},
	recast: function () {
		var v1 = new THREE.Vector3();
		return function ( t ) {
			this.origin.copy( this.at( t, v1 ) );
			return this;
		};
	}(),
	closestPointToPoint: function ( point, optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		result.subVectors( point, this.origin );
		var directionDistance = result.dot( this.direction );
		if ( directionDistance < 0 ) {
			return result.copy( this.origin );
		}
		return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
	},
	distanceToPoint: function () {
		var v1 = new THREE.Vector3();
		return function ( point ) {
			var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
						if ( directionDistance < 0 ) {
				return this.origin.distanceTo( point );
			}
			v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
			return v1.distanceTo( point );
		};
	}(),
	distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
														var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 );
		var segDir = v1.clone().sub( v0 ).normalize();
		var segExtent = v0.distanceTo( v1 ) * 0.5;
		var diff = this.origin.clone().sub( segCenter );
		var a01 = - this.direction.dot( segDir );
		var b0 = diff.dot( this.direction );
		var b1 = - diff.dot( segDir );
		var c = diff.lengthSq();
		var det = Math.abs( 1 - a01 * a01 );
		var s0, s1, sqrDist, extDet;
		if ( det >= 0 ) {
						s0 = a01 * b1 - b0;
			s1 = a01 * b0 - b1;
			extDet = segExtent * det;
			if ( s0 >= 0 ) {
				if ( s1 >= - extDet ) {
					if ( s1 <= extDet ) {
																		var invDet = 1 / det;
						s0 *= invDet;
						s1 *= invDet;
						sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
					} else {
												s1 = segExtent;
						s0 = Math.max( 0, - ( a01 * s1 + b0) );
						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
					}
				} else {
										s1 = - segExtent;
					s0 = Math.max( 0, - ( a01 * s1 + b0) );
					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
				}
			} else {
				if ( s1 <= - extDet) {
										s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
					s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
				} else if ( s1 <= extDet ) {
										s0 = 0;
					s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
					sqrDist = s1 * ( s1 + 2 * b1 ) + c;
				} else {
										s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
					s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
				}
			}
		} else {
						s1 = ( a01 > 0 ) ? - segExtent : segExtent;
			s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
			sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
		}
		if ( optionalPointOnRay ) {
			optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) );
		}
		if ( optionalPointOnSegment ) {
			optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) );
		}
		return sqrDist;
	},
	isIntersectionSphere: function ( sphere ) {
		return this.distanceToPoint( sphere.center ) <= sphere.radius;
	},
	isIntersectionPlane: function ( plane ) {
				var distToPoint = plane.distanceToPoint( this.origin );
		if ( distToPoint === 0 ) {
			return true;
		}
		var denominator = plane.normal.dot( this.direction );
		if ( denominator * distToPoint < 0 ) {
			return true
		}
				return false;
	},
	distanceToPlane: function ( plane ) {
		var denominator = plane.normal.dot( this.direction );
		if ( denominator == 0 ) {
						if( plane.distanceToPoint( this.origin ) == 0 ) {
				return 0;
			}
						return null;
		}
		var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
				return t >= 0 ? t :  null;
	},
	intersectPlane: function ( plane, optionalTarget ) {
		var t = this.distanceToPlane( plane );
		if ( t === null ) {
			return null;
		}
		return this.at( t, optionalTarget );
	},
	applyMatrix4: function ( matrix4 ) {
		this.direction.add( this.origin ).applyMatrix4( matrix4 );
		this.origin.applyMatrix4( matrix4 );
		this.direction.sub( this.origin );
		return this;
	},
	equals: function ( ray ) {
		return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
	},
	clone: function () {
		return new THREE.Ray().copy( this );
	}
};
THREE.Sphere = function ( center, radius ) {
	this.center = ( center !== undefined ) ? center : new THREE.Vector3();
	this.radius = ( radius !== undefined ) ? radius : 0;
};
THREE.Sphere.prototype = {
	constructor: THREE.Sphere,
	set: function ( center, radius ) {
		this.center.copy( center );
		this.radius = radius;
		return this;
	},
	setFromPoints: function ( points ) {
		var radiusSq, maxRadiusSq = 0;
		for ( var i = 0, il = points.length; i < il; i ++ ) {
			radiusSq = points[ i ].lengthSq();
			maxRadiusSq = Math.max( maxRadiusSq, radiusSq );
		}
		this.center.set( 0, 0, 0 );
		this.radius = Math.sqrt( maxRadiusSq );
		return this;
	},
	copy: function ( sphere ) {
		this.center.copy( sphere.center );
		this.radius = sphere.radius;
		return this;
	},
	empty: function () {
		return ( this.radius <= 0 );
	},
	containsPoint: function ( point ) {
		return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
	},
	distanceToPoint: function ( point ) {
		return ( point.distanceTo( this.center ) - this.radius );
	},
	intersectsSphere: function ( sphere ) {
		var radiusSum = this.radius + sphere.radius;
		return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
	},
	clampPoint: function ( point, optionalTarget ) {
		var deltaLengthSq = this.center.distanceToSquared( point );
		var result = optionalTarget || new THREE.Vector3();
		result.copy( point );
		if ( deltaLengthSq > ( this.radius * this.radius ) ) {
			result.sub( this.center ).normalize();
			result.multiplyScalar( this.radius ).add( this.center );
		}
		return result;
	},
	getBoundingBox: function ( optionalTarget ) {
		var box = optionalTarget || new THREE.Box3();
		box.set( this.center, this.center );
		box.expandByScalar( this.radius );
		return box;
	},
	applyMatrix4: function ( matrix ) {
		this.center.applyMatrix4( matrix );
		this.radius = this.radius * matrix.getMaxScaleOnAxis();
		return this;
	},
	translate: function ( offset ) {
		this.center.add( offset );
		return this;
	},
	equals: function ( sphere ) {
		return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
	},
	clone: function () {
		return new THREE.Sphere().copy( this );
	}
};
THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) {
	this.planes = [
		( p0 !== undefined ) ? p0 : new THREE.Plane(),
		( p1 !== undefined ) ? p1 : new THREE.Plane(),
		( p2 !== undefined ) ? p2 : new THREE.Plane(),
		( p3 !== undefined ) ? p3 : new THREE.Plane(),
		( p4 !== undefined ) ? p4 : new THREE.Plane(),
		( p5 !== undefined ) ? p5 : new THREE.Plane()
	];
};
THREE.Frustum.prototype = {
	constructor: THREE.Frustum,
	set: function ( p0, p1, p2, p3, p4, p5 ) {
		var planes = this.planes;
		planes[0].copy( p0 );
		planes[1].copy( p1 );
		planes[2].copy( p2 );
		planes[3].copy( p3 );
		planes[4].copy( p4 );
		planes[5].copy( p5 );
		return this;
	},
	copy: function ( frustum ) {
		var planes = this.planes;
		for( var i = 0; i < 6; i ++ ) {
			planes[i].copy( frustum.planes[i] );
		}
		return this;
	},
	setFromMatrix: function ( m ) {
		var planes = this.planes;
		var me = m.elements;
		var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
		var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
		var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
		var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];
		planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
		planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
		planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
		planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
		planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
		planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
		return this;
	},
	intersectsObject: function () {
		var center = new THREE.Vector3();
		return function ( object ) {
						var geometry = object.geometry;
			var matrix = object.matrixWorld;
			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
			var negRadius = - geometry.boundingSphere.radius * matrix.getMaxScaleOnAxis();
			center.getPositionFromMatrix( matrix );
			var planes = this.planes;
			for ( var i = 0; i < 6; i ++ ) {
				var distance = planes[ i ].distanceToPoint( center );
				if ( distance < negRadius ) {
					return false;
				}
			}
			return true;
		};
	}(),
	intersectsSphere: function ( sphere ) {
		var planes = this.planes;
		var center = sphere.center;
		var negRadius = -sphere.radius;
		for ( var i = 0; i < 6; i ++ ) {
			var distance = planes[ i ].distanceToPoint( center );
			if ( distance < negRadius ) {
				return false;
			}
		}
		return true;
	},
	intersectsBox : function() {
		var p1 = new THREE.Vector3(),
			p2 = new THREE.Vector3();
		return function( box ) {
			var planes = this.planes;
			
			for ( var i = 0; i < 6 ; i ++ ) {
			
				var plane = planes[i];
				
				p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
				p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
				p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
				p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
				p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
				p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;
				var d1 = plane.distanceToPoint( p1 );
				var d2 = plane.distanceToPoint( p2 );
				
								if ( d1 < 0 && d2 < 0 ) {
					
					return false;
		
				}
			}
			return true;
		};
	}(),
	containsPoint: function ( point ) {
		var planes = this.planes;
		for ( var i = 0; i < 6; i ++ ) {
			if ( planes[ i ].distanceToPoint( point ) < 0 ) {
				return false;
			}
		}
		return true;
	},
	clone: function () {
		return new THREE.Frustum().copy( this );
	}
};
THREE.Plane = function ( normal, constant ) {
	this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 );
	this.constant = ( constant !== undefined ) ? constant : 0;
};
THREE.Plane.prototype = {
	constructor: THREE.Plane,
	set: function ( normal, constant ) {
		this.normal.copy( normal );
		this.constant = constant;
		return this;
	},
	setComponents: function ( x, y, z, w ) {
		this.normal.set( x, y, z );
		this.constant = w;
		return this;
	},
	setFromNormalAndCoplanarPoint: function ( normal, point ) {
		this.normal.copy( normal );
		this.constant = - point.dot( this.normal );			return this;
	},
	setFromCoplanarPoints: function() {
		var v1 = new THREE.Vector3();
		var v2 = new THREE.Vector3();
		return function ( a, b, c ) {
			var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
						this.setFromNormalAndCoplanarPoint( normal, a );
			return this;
		};
	}(),
	copy: function ( plane ) {
		this.normal.copy( plane.normal );
		this.constant = plane.constant;
		return this;
	},
	normalize: function () {
				var inverseNormalLength = 1.0 / this.normal.length();
		this.normal.multiplyScalar( inverseNormalLength );
		this.constant *= inverseNormalLength;
		return this;
	},
	negate: function () {
		this.constant *= -1;
		this.normal.negate();
		return this;
	},
	distanceToPoint: function ( point ) {
		return this.normal.dot( point ) + this.constant;
	},
	distanceToSphere: function ( sphere ) {
		return this.distanceToPoint( sphere.center ) - sphere.radius;
	},
	projectPoint: function ( point, optionalTarget ) {
		return this.orthoPoint( point, optionalTarget ).sub( point ).negate();
	},
	orthoPoint: function ( point, optionalTarget ) {
		var perpendicularMagnitude = this.distanceToPoint( point );
		var result = optionalTarget || new THREE.Vector3();
		return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );
	},
	isIntersectionLine: function ( line ) {
				var startSign = this.distanceToPoint( line.start );
		var endSign = this.distanceToPoint( line.end );
		return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
	},
	intersectLine: function() {
		var v1 = new THREE.Vector3();
		return function ( line, optionalTarget ) {
			var result = optionalTarget || new THREE.Vector3();
			var direction = line.delta( v1 );
			var denominator = this.normal.dot( direction );
			if ( denominator == 0 ) {
								if( this.distanceToPoint( line.start ) == 0 ) {
					return result.copy( line.start );
				}
								return undefined;
			}
			var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
			if( t < 0 || t > 1 ) {
				return undefined;
			}
			return result.copy( direction ).multiplyScalar( t ).add( line.start );
		};
	}(),
	coplanarPoint: function ( optionalTarget ) {
		var result = optionalTarget || new THREE.Vector3();
		return result.copy( this.normal ).multiplyScalar( - this.constant );
	},
	applyMatrix4: function() {
		var v1 = new THREE.Vector3();
		var v2 = new THREE.Vector3();
		return function ( matrix, optionalNormalMatrix ) {
									optionalNormalMatrix = optionalNormalMatrix || new THREE.Matrix3().getNormalMatrix( matrix );
			var newNormal = v1.copy( this.normal ).applyMatrix3( optionalNormalMatrix );
			var newCoplanarPoint = this.coplanarPoint( v2 );
			newCoplanarPoint.applyMatrix4( matrix );
			this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint );
			return this;
		};
	}(),
	translate: function ( offset ) {
		this.constant = this.constant - offset.dot( this.normal );
		return this;
	},
	equals: function ( plane ) {
		return plane.normal.equals( this.normal ) && ( plane.constant == this.constant );
	},
	clone: function () {
		return new THREE.Plane().copy( this );
	}
};
THREE.Math = {
	PI2: Math.PI * 2,
	generateUUID: function () {
				
		var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
		var uuid = new Array(36);
		var rnd = 0, r;
		return function () {
			for ( var i = 0; i < 36; i ++ ) {
				if ( i == 8 || i == 13 || i == 18 || i == 23 ) {
			
					uuid[ i ] = '-';
			
				} else if ( i == 14 ) {
			
					uuid[ i ] = '4';
			
				} else {
			
					if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
					r = rnd & 0xf;
					rnd = rnd >> 4;
					uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
				}
			}
			
			return uuid.join('');
		};
	}(),
		clamp: function ( x, a, b ) {
		return ( x < a ) ? a : ( ( x > b ) ? b : x );
	},
		clampBottom: function ( x, a ) {
		return x < a ? a : x;
	},
		mapLinear: function ( x, a1, a2, b1, b2 ) {
		return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
	},
		smoothstep: function ( x, min, max ) {
		if ( x <= min ) return 0;
		if ( x >= max ) return 1;
		x = ( x - min )/( max - min );
		return x*x*(3 - 2*x);
	},
	smootherstep: function ( x, min, max ) {
		if ( x <= min ) return 0;
		if ( x >= max ) return 1;
		x = ( x - min )/( max - min );
		return x*x*x*(x*(x*6 - 15) + 10);
	},
			random16: function () {
		return ( 65280 * Math.random() + 255 * Math.random() ) / 65535;
	},
		randInt: function ( low, high ) {
		return low + Math.floor( Math.random() * ( high - low + 1 ) );
	},
		randFloat: function ( low, high ) {
		return low + Math.random() * ( high - low );
	},
		randFloatSpread: function ( range ) {
		return range * ( 0.5 - Math.random() );
	},
	sign: function ( x ) {
		return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 );
	},
	degToRad: function() {
		var degreeToRadiansFactor = Math.PI / 180;
		return function ( degrees ) {
			return degrees * degreeToRadiansFactor;
		};
	}(),
	radToDeg: function() {
		var radianToDegreesFactor = 180 / Math.PI;
		return function ( radians ) {
			return radians * radianToDegreesFactor;
		};
	}()
};


THREE.Triangle = function ( a, b, c ) {

	this.a = ( a !== undefined ) ? a : new THREE.Vector3();
	this.b = ( b !== undefined ) ? b : new THREE.Vector3();
	this.c = ( c !== undefined ) ? c : new THREE.Vector3();

};

THREE.Triangle.normal = function() {

	var v0 = new THREE.Vector3();

	return function ( a, b, c, optionalTarget ) {

		var result = optionalTarget || new THREE.Vector3();

		result.subVectors( c, b );
		v0.subVectors( a, b );
		result.cross( v0 );

		var resultLengthSq = result.lengthSq();
		if( resultLengthSq > 0 ) {

			return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );

		}

		return result.set( 0, 0, 0 );

	};

}();

// static/instance method to calculate barycoordinates
// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
THREE.Triangle.barycoordFromPoint = function() {

	var v0 = new THREE.Vector3();
	var v1 = new THREE.Vector3();
	var v2 = new THREE.Vector3();

	return function ( point, a, b, c, optionalTarget ) {

		v0.subVectors( c, a );
		v1.subVectors( b, a );
		v2.subVectors( point, a );

		var dot00 = v0.dot( v0 );
		var dot01 = v0.dot( v1 );
		var dot02 = v0.dot( v2 );
		var dot11 = v1.dot( v1 );
		var dot12 = v1.dot( v2 );

		var denom = ( dot00 * dot11 - dot01 * dot01 );

		var result = optionalTarget || new THREE.Vector3();

		// colinear or singular triangle
		if( denom == 0 ) {
			// arbitrary location outside of triangle?
			// not sure if this is the best idea, maybe should be returning undefined
			return result.set( -2, -1, -1 );
		}

		var invDenom = 1 / denom;
		var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
		var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;

		// barycoordinates must always sum to 1
		return result.set( 1 - u - v, v, u );

	};

}();

THREE.Triangle.containsPoint = function() {

	var v1 = new THREE.Vector3();

	return function ( point, a, b, c ) {

		var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 );

		return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );

	};

}();

THREE.Triangle.prototype = {

	constructor: THREE.Triangle,

	set: function ( a, b, c ) {

		this.a.copy( a );
		this.b.copy( b );
		this.c.copy( c );

		return this;

	},

	setFromPointsAndIndices: function ( points, i0, i1, i2 ) {

		this.a.copy( points[i0] );
		this.b.copy( points[i1] );
		this.c.copy( points[i2] );

		return this;

	},

	copy: function ( triangle ) {

		this.a.copy( triangle.a );
		this.b.copy( triangle.b );
		this.c.copy( triangle.c );

		return this;

	},

	area: function() {

		var v0 = new THREE.Vector3();
		var v1 = new THREE.Vector3();

		return function () {

			v0.subVectors( this.c, this.b );
			v1.subVectors( this.a, this.b );

			return v0.cross( v1 ).length() * 0.5;

		};

	}(),

	midpoint: function ( optionalTarget ) {

		var result = optionalTarget || new THREE.Vector3();
		return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );

	},

	normal: function ( optionalTarget ) {

		return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget );

	},

	plane: function ( optionalTarget ) {

		var result = optionalTarget || new THREE.Plane();

		return result.setFromCoplanarPoints( this.a, this.b, this.c );

	},

	barycoordFromPoint: function ( point, optionalTarget ) {

		return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );

	},

	containsPoint: function ( point ) {

		return THREE.Triangle.containsPoint( point, this.a, this.b, this.c );

	},

	equals: function ( triangle ) {

		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );

	},

	clone: function () {

		return new THREE.Triangle().copy( this );

	}

};


THREE.UV = function ( u, v ) {
	return new THREE.Vector2( u, v );
};
THREE.EventDispatcher = function () {}
THREE.EventDispatcher.prototype = {
	constructor: THREE.EventDispatcher,
	apply: function ( object ) {
		object.addEventListener = THREE.EventDispatcher.prototype.addEventListener;
		object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener;
		object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener;
		object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent;
	},
	addEventListener: function ( type, listener ) {
		if ( this._listeners === undefined ) this._listeners = {};
		var listeners = this._listeners;
		if ( listeners[ type ] === undefined ) {
			listeners[ type ] = [];
		}
		if ( listeners[ type ].indexOf( listener ) === - 1 ) {
			listeners[ type ].push( listener );
		}
	},
	hasEventListener: function ( type, listener ) {
		if ( this._listeners === undefined ) return false;
		var listeners = this._listeners;
		if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
			return true;
		}
		return false;
	},
	removeEventListener: function ( type, listener ) {
		if ( this._listeners === undefined ) return;
		var listeners = this._listeners;
		var index = listeners[ type ].indexOf( listener );
		if ( index !== - 1 ) {
			listeners[ type ].splice( index, 1 );
		}
	},
	dispatchEvent: function ( event ) {
		if ( this._listeners === undefined ) return;
		var listeners = this._listeners;
		var listenerArray = listeners[ event.type ];
		if ( listenerArray !== undefined ) {
			event.target = this;
			for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
				listenerArray[ i ].call( this, event );
			}
		}
	}
};
( function ( THREE ) {
	THREE.Raycaster = function ( origin, direction, near, far ) {
		this.ray = new THREE.Ray( origin, direction );
				if ( this.ray.direction.lengthSq() > 0 ) {
			this.ray.direction.normalize();
		}
		this.near = near || 0;
		this.far = far || Infinity;
	};
	var sphere = new THREE.Sphere();
	var localRay = new THREE.Ray();
	var facePlane = new THREE.Plane();
	var intersectPoint = new THREE.Vector3();
	var matrixPosition = new THREE.Vector3();
	var inverseMatrix = new THREE.Matrix4();
	var descSort = function ( a, b ) {
		return a.distance - b.distance;
	};
	var intersectObject = function ( object, raycaster, intersects ) {
		if ( object instanceof THREE.Mesh ) {
			var geometry = object.geometry;
						matrixPosition.getPositionFromMatrix( object.matrixWorld );
			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
			sphere.set( matrixPosition, geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis() );
			if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {
				return intersects;
			}
			var vertices = geometry.vertices;
			if ( geometry instanceof THREE.BufferGeometry ) {
				var material = object.material;
				if ( material === undefined ) return intersects;
				if ( geometry.dynamic === false ) return intersects;
				var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
				var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
				var side = object.material.side;
				var a, b, c;
				var precision = raycaster.precision;
				inverseMatrix.getInverse( object.matrixWorld );
				localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
				var fl;
				var indexed = false;
				if ( geometry.attributes.index ) {
					indexed = true;
					fl = geometry.attributes.index.numItems / 3;
				} else {
					fl = geometry.attributes.position.numItems / 9;
				}
				var vA = new THREE.Vector3();
				var vB = new THREE.Vector3();
				var vC = new THREE.Vector3();
				var vCB = new THREE.Vector3();
				var vAB = new THREE.Vector3();
				for ( var oi = 0; oi < geometry.offsets.length; ++oi ) {
					var start = geometry.offsets[ oi ].start;
					var count = geometry.offsets[ oi ].count;
					var index = geometry.offsets[ oi ].index;
					for ( var i = start, il = start + count; i < il; i += 3 ) {
						if ( indexed ) {
							a = index + geometry.attributes.index.array[ i ];
							b = index + geometry.attributes.index.array[ i + 1 ];
							c = index + geometry.attributes.index.array[ i + 2 ];
						} else {
							a = index;
							b = index + 1;
							c = index + 2;
						}
						vA.set(
							geometry.attributes.position.array[ a * 3 ],
							geometry.attributes.position.array[ a * 3 + 1 ],
							geometry.attributes.position.array[ a * 3 + 2 ]
						);
						vB.set(
							geometry.attributes.position.array[ b * 3 ],
							geometry.attributes.position.array[ b * 3 + 1 ],
							geometry.attributes.position.array[ b * 3 + 2 ]
						);
						vC.set(
							geometry.attributes.position.array[ c * 3 ],
							geometry.attributes.position.array[ c * 3 + 1 ],
							geometry.attributes.position.array[ c * 3 + 2 ]
						);
						facePlane.setFromCoplanarPoints( vA, vB, vC );
						var planeDistance = localRay.distanceToPlane( facePlane );
												if ( planeDistance < precision ) continue;
												if ( planeDistance === null ) continue;
												side = material.side;
						if ( side !== THREE.DoubleSide ) {
							var planeSign = localRay.direction.dot( facePlane.normal );
							
							if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) {
								continue;
							}
						}
																		if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) {
							continue;
						}
												intersectPoint = localRay.at( planeDistance, intersectPoint );
						if ( THREE.Triangle.containsPoint( intersectPoint, vA, vB, vC ) === false ) {
							continue;
						}
						intersects.push( {
																					distance: planeDistance,
							point: raycaster.ray.at( planeDistance ),
							face: null,
							faceIndex: null,
							object: object
						} );
					}
				}
			} else if ( geometry instanceof THREE.Geometry ) {
				var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
				var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
				var side = object.material.side;
				var a, b, c, d;
				var precision = raycaster.precision;
				inverseMatrix.getInverse( object.matrixWorld );
				localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
				for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
					var face = geometry.faces[ f ];
					var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material;
					if ( material === undefined ) continue;
					facePlane.setFromNormalAndCoplanarPoint( face.normal, vertices[face.a] );
					var planeDistance = localRay.distanceToPlane( facePlane );
										if ( planeDistance < precision ) continue;
										if ( planeDistance === null ) continue;
										side = material.side;
					if ( side !== THREE.DoubleSide ) {
						var planeSign = localRay.direction.dot( facePlane.normal );
						if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) {
							continue;
						}
					}
															if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue;
										intersectPoint = localRay.at( planeDistance, intersectPoint );
					if ( face instanceof THREE.Face3 ) {
						a = vertices[ face.a ];
						b = vertices[ face.b ];
						c = vertices[ face.c ];
						if ( THREE.Triangle.containsPoint( intersectPoint, a, b, c ) === false ) {
							continue;
						}
					} else if ( face instanceof THREE.Face4 ) {
						a = vertices[ face.a ];
						b = vertices[ face.b ];
						c = vertices[ face.c ];
						d = vertices[ face.d ];
						if ( THREE.Triangle.containsPoint( intersectPoint, a, b, d ) === false &&
						     THREE.Triangle.containsPoint( intersectPoint, b, c, d ) === false ) {
							continue;
						}
					} else {
																								throw Error( "face type not supported" );
					}
					intersects.push( {
																		distance: planeDistance,
						point: raycaster.ray.at( planeDistance ),
						face: face,
						faceIndex: f,
						object: object
					} );
				}
			}
		} 
	};
	var intersectDescendants = function ( object, raycaster, intersects ) {
		var descendants = object.getDescendants();
		for ( var i = 0, l = descendants.length; i < l; i ++ ) {
			intersectObject( descendants[ i ], raycaster, intersects );
		}
	};
		THREE.Raycaster.prototype.precision = 0.0001;
	THREE.Raycaster.prototype.linePrecision = 1;
	THREE.Raycaster.prototype.set = function ( origin, direction ) {
		this.ray.set( origin, direction );
				if ( this.ray.direction.length() > 0 ) {
			this.ray.direction.normalize();
		}
	};
	THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) {
		var intersects = [];
		if ( recursive === true ) {
			intersectDescendants( object, this, intersects );
		}
		intersectObject( object, this, intersects );
		intersects.sort( descSort );
		return intersects;
	};
	THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) {
		var intersects = [];
		for ( var i = 0, l = objects.length; i < l; i ++ ) {
			intersectObject( objects[ i ], this, intersects );
			if ( recursive === true ) {
				intersectDescendants( objects[ i ], this, intersects );
			}
		}
		intersects.sort( descSort );
		return intersects;
	};
}( THREE ) );
THREE.Object3D = function () {
	this.id = THREE.Object3DIdCount ++;
	this.uuid = THREE.Math.generateUUID();
	this.name = '';
	this.parent = undefined;
	this.children = [];
	this.up = new THREE.Vector3( 0, 1, 0 );
	this.position = new THREE.Vector3();
	this.rotation = new THREE.Euler();
	this.quaternion = new THREE.Quaternion();
	this.scale = new THREE.Vector3( 1, 1, 1 );
		this.rotation._quaternion = this.quaternion;
	this.quaternion._euler = this.rotation;
	this.renderDepth = null;
	this.rotationAutoUpdate = true;
	this.matrix = new THREE.Matrix4();
	this.matrixWorld = new THREE.Matrix4();
	this.matrixAutoUpdate = true;
	this.matrixWorldNeedsUpdate = true;
	this.visible = true;
	this.castShadow = false;
	this.receiveShadow = false;
	this.frustumCulled = true;
	this.userData = {};
};
THREE.Object3D.prototype = {
	constructor: THREE.Object3D,
	get eulerOrder () {
		console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' );
		return this.rotation.order;
	},
	set eulerOrder ( value ) {
		console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' );
		this.rotation.order = value;
	},
	get useQuaternion () {
		console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' );
	},
	set useQuaternion ( value ) {
		console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' );
	},
	applyMatrix: function () {
		var m1 = new THREE.Matrix4();
		return function ( matrix ) {
			this.matrix.multiplyMatrices( matrix, this.matrix );
			this.position.getPositionFromMatrix( this.matrix );
			this.scale.getScaleFromMatrix( this.matrix );
			m1.extractRotation( this.matrix );
			this.quaternion.setFromRotationMatrix( m1 );
		}
	}(),
	setRotationFromAxisAngle: function ( axis, angle ) {
				this.quaternion.setFromAxisAngle( axis, angle );
	},
	setRotationFromEuler: function ( euler ) {
		this.quaternion.setFromEuler( euler, true );
	},
	setRotationFromMatrix: function ( m ) {
				this.quaternion.setFromRotationMatrix( m );
	},
	setRotationFromQuaternion: function ( q ) {
				this.quaternion.copy( q );
	},
	rotateOnAxis: function() {
						var q1 = new THREE.Quaternion();
		return function ( axis, angle ) {
			q1.setFromAxisAngle( axis, angle );
			this.quaternion.multiply( q1 );
			return this;
		}
	}(),
	rotateX: function () {
		var v1 = new THREE.Vector3( 1, 0, 0 );
		return function ( angle ) {
			return this.rotateOnAxis( v1, angle );
		};
	}(),
	rotateY: function () {
		var v1 = new THREE.Vector3( 0, 1, 0 );
		return function ( angle ) {
			return this.rotateOnAxis( v1, angle );
		};
	}(),
	rotateZ: function () {
		var v1 = new THREE.Vector3( 0, 0, 1 );
		return function ( angle ) {
			return this.rotateOnAxis( v1, angle );
		};
	}(),
	translateOnAxis: function () {
						var v1 = new THREE.Vector3();
		return function ( axis, distance ) {
			v1.copy( axis );
			v1.applyQuaternion( this.quaternion );
			this.position.add( v1.multiplyScalar( distance ) );
			return this;
		}
	}(),
	translate: function ( distance, axis ) {
		console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' );
		return this.translateOnAxis( axis, distance );
	},
	translateX: function () {
		var v1 = new THREE.Vector3( 1, 0, 0 );
		return function ( distance ) {
			return this.translateOnAxis( v1, distance );
		};
	}(),
	translateY: function () {
		var v1 = new THREE.Vector3( 0, 1, 0 );
		return function ( distance ) {
			return this.translateOnAxis( v1, distance );
		};
	}(),
	translateZ: function () {
		var v1 = new THREE.Vector3( 0, 0, 1 );
		return function ( distance ) {
			return this.translateOnAxis( v1, distance );
		};
	}(),
	localToWorld: function ( vector ) {
		return vector.applyMatrix4( this.matrixWorld );
	},
	worldToLocal: function () {
		var m1 = new THREE.Matrix4();
		return function ( vector ) {
			return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
		};
	}(),
	lookAt: function () {
				var m1 = new THREE.Matrix4();
		return function ( vector ) {
			m1.lookAt( vector, this.position, this.up );
			this.quaternion.setFromRotationMatrix( m1 );
		};
	}(),
	add: function ( object ) {
		if ( object === this ) {
			console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' );
			return;
		}
		if ( object instanceof THREE.Object3D ) {
			if ( object.parent !== undefined ) {
				object.parent.remove( object );
			}
			object.parent = this;
			object.dispatchEvent( { type: 'added' } );
			this.children.push( object );
						var scene = this;
			while ( scene.parent !== undefined ) {
				scene = scene.parent;
			}
			if ( scene !== undefined && scene instanceof THREE.Scene )  {
				scene.__addObject( object );
			}
		}
	},
	remove: function ( object ) {
		var index = this.children.indexOf( object );
		if ( index !== - 1 ) {
			object.parent = undefined;
			object.dispatchEvent( { type: 'removed' } );
			this.children.splice( index, 1 );
						var scene = this;
			while ( scene.parent !== undefined ) {
				scene = scene.parent;
			}
			if ( scene !== undefined && scene instanceof THREE.Scene ) {
				scene.__removeObject( object );
			}
		}
	},
	traverse: function ( callback ) {
		callback( this );
		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
			this.children[ i ].traverse( callback );
		}
	},
	getObjectById: function ( id, recursive ) {
		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
			var child = this.children[ i ];
			if ( child.id === id ) {
				return child;
			}
			if ( recursive === true ) {
				child = child.getObjectById( id, recursive );
				if ( child !== undefined ) {
					return child;
				}
			}
		}
		return undefined;
	},
	getObjectByName: function ( name, recursive ) {
		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
			var child = this.children[ i ];
			if ( child.name === name ) {
				return child;
			}
			if ( recursive === true ) {
				child = child.getObjectByName( name, recursive );
				if ( child !== undefined ) {
					return child;
				}
			}
		}
		return undefined;
	},
	getChildByName: function ( name, recursive ) {
		console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' );
		return this.getObjectByName( name, recursive );
	},
	getDescendants: function ( array ) {
		if ( array === undefined ) array = [];
		Array.prototype.push.apply( array, this.children );
		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
			this.children[ i ].getDescendants( array );
		}
		return array;
	},
	updateMatrix: function () {
		this.matrix.compose( this.position, this.quaternion, this.scale );
		this.matrixWorldNeedsUpdate = true;
	},
	updateMatrixWorld: function ( force ) {
		if ( this.matrixAutoUpdate === true ) this.updateMatrix();
		if ( this.matrixWorldNeedsUpdate === true || force === true ) {
			if ( this.parent === undefined ) {
				this.matrixWorld.copy( this.matrix );
			} else {
				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
			}
			this.matrixWorldNeedsUpdate = false;
			force = true;
		}
				for ( var i = 0, l = this.children.length; i < l; i ++ ) {
			this.children[ i ].updateMatrixWorld( force );
		}
	},
	clone: function ( object, recursive ) {
		if ( object === undefined ) object = new THREE.Object3D();
		if ( recursive === undefined ) recursive = true;
		object.name = this.name;
		object.up.copy( this.up );
		object.position.copy( this.position );
		object.quaternion.copy( this.quaternion );
		object.scale.copy( this.scale );
		object.renderDepth = this.renderDepth;
		object.rotationAutoUpdate = this.rotationAutoUpdate;
		object.matrix.copy( this.matrix );
		object.matrixWorld.copy( this.matrixWorld );
		object.matrixAutoUpdate = this.matrixAutoUpdate;
		object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;
		object.visible = this.visible;
		object.castShadow = this.castShadow;
		object.receiveShadow = this.receiveShadow;
		object.frustumCulled = this.frustumCulled;
		object.userData = JSON.parse( JSON.stringify( this.userData ) );
		if ( recursive === true ) {
			for ( var i = 0; i < this.children.length; i ++ ) {
				var child = this.children[ i ];
				object.add( child.clone() );
			}
		}
		return object;
	}
};
THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype );
THREE.Object3DIdCount = 0;
THREE.Projector = function () {
	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
	_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
	_face, _face3Count, _face3Pool = [], _face3PoolLength = 0,
	_face4Count, _face4Pool = [], _face4PoolLength = 0,
	_line, _lineCount, _linePool = [], _linePoolLength = 0,
	_particle, _particleCount, _particlePool = [], _particlePoolLength = 0,
	_renderData = { objects: [], sprites: [], lights: [], elements: [] },
	_vector3 = new THREE.Vector3(),
	_vector4 = new THREE.Vector4(),
	_clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ),
	_boundingBox = new THREE.Box3(),
	_points3 = new Array( 3 ),
	_points4 = new Array( 4 ),
	_viewMatrix = new THREE.Matrix4(),
	_viewProjectionMatrix = new THREE.Matrix4(),
	_modelMatrix,
	_modelViewProjectionMatrix = new THREE.Matrix4(),
	_normalMatrix = new THREE.Matrix3(),
	_normalViewMatrix = new THREE.Matrix3(),
	_centroid = new THREE.Vector3(),
	_frustum = new THREE.Frustum(),
	_clippedVertex1PositionScreen = new THREE.Vector4(),
	_clippedVertex2PositionScreen = new THREE.Vector4();
	this.projectVector = function ( vector, camera ) {
		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
		return vector.applyProjection( _viewProjectionMatrix );
	};
	this.unprojectVector = function ( vector, camera ) {
		camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );
		_viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, camera.projectionMatrixInverse );
		return vector.applyProjection( _viewProjectionMatrix );
	};
	this.pickingRay = function ( vector, camera ) {
				vector.z = -1.0;
		var end = new THREE.Vector3( vector.x, vector.y, 1.0 );
		this.unprojectVector( vector, camera );
		this.unprojectVector( end, camera );
				end.sub( vector ).normalize();
		return new THREE.Raycaster( vector, end );
	};
	var getObject = function ( object ) {
		_object = getNextObjectInPool();
		_object.id = object.id;
		_object.object = object;
		if ( object.renderDepth !== null ) {
			_object.z = object.renderDepth;
		} else {
			_vector3.getPositionFromMatrix( object.matrixWorld );
			_vector3.applyProjection( _viewProjectionMatrix );
			_object.z = _vector3.z;
		}
		return _object;
	};
	var projectObject = function ( object ) {
		if ( object.visible === false ) return;
		if ( object instanceof THREE.Light ) {
			_renderData.lights.push( object );
		} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) {
			if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
				_renderData.objects.push( getObject( object ) );
			}
		} else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) {
			_renderData.sprites.push( getObject( object ) );
		}
		for ( var i = 0, l = object.children.length; i < l; i ++ ) {
			projectObject( object.children[ i ] );
		}
	};
	var projectGraph = function ( root, sortObjects ) {
		_objectCount = 0;
		_renderData.objects.length = 0;
		_renderData.sprites.length = 0;
		_renderData.lights.length = 0;
		projectObject( root );
		if ( sortObjects === true ) {
			_renderData.objects.sort( painterSort );
		}
	};
	this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
		var visible = false,
		o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object,
		geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs,
		v1, v2, v3, v4, isFaceMaterial, objectMaterials;
		_face3Count = 0;
		_face4Count = 0;
		_lineCount = 0;
		_particleCount = 0;
		_renderData.elements.length = 0;
		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
		if ( camera.parent === undefined ) camera.updateMatrixWorld();
		_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
		_normalViewMatrix.getNormalMatrix( _viewMatrix );
		_frustum.setFromMatrix( _viewProjectionMatrix );
		projectGraph( scene, sortObjects );
		for ( o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
			object = _renderData.objects[ o ].object;
			_modelMatrix = object.matrixWorld;
			_vertexCount = 0;
			if ( object instanceof THREE.Mesh ) {
				geometry = object.geometry;
				vertices = geometry.vertices;
				faces = geometry.faces;
				faceVertexUvs = geometry.faceVertexUvs;
				_normalMatrix.getNormalMatrix( _modelMatrix );
				isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
				objectMaterials = isFaceMaterial === true ? object.material : null;
				for ( v = 0, vl = vertices.length; v < vl; v ++ ) {
					_vertex = getNextVertexInPool();
					_vertex.positionWorld.copy( vertices[ v ] ).applyMatrix4( _modelMatrix );
					_vertex.positionScreen.copy( _vertex.positionWorld ).applyMatrix4( _viewProjectionMatrix );
					var invW = 1 / _vertex.positionScreen.w;
					_vertex.positionScreen.x *= invW;
					_vertex.positionScreen.y *= invW;
					_vertex.positionScreen.z *= invW;
					_vertex.visible = ! ( _vertex.positionScreen.x < -1 || _vertex.positionScreen.x > 1 ||
							      _vertex.positionScreen.y < -1 || _vertex.positionScreen.y > 1 ||
							      _vertex.positionScreen.z < -1 || _vertex.positionScreen.z > 1 );
				}
				for ( f = 0, fl = faces.length; f < fl; f ++ ) {
					face = faces[ f ];
					var material = isFaceMaterial === true
						? objectMaterials.materials[ face.materialIndex ]
						: object.material;
					if ( material === undefined ) continue;
					var side = material.side;
					if ( face instanceof THREE.Face3 ) {
						v1 = _vertexPool[ face.a ];
						v2 = _vertexPool[ face.b ];
						v3 = _vertexPool[ face.c ];
						_points3[ 0 ] = v1.positionScreen;
						_points3[ 1 ] = v2.positionScreen;
						_points3[ 2 ] = v3.positionScreen;
						if ( v1.visible === true || v2.visible === true || v3.visible === true ||
							_clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) {
							visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
								( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
							if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
								_face = getNextFace3InPool();
								_face.id = object.id;
								_face.v1.copy( v1 );
								_face.v2.copy( v2 );
								_face.v3.copy( v3 );
							} else {
								continue;
							}
						} else {
							continue;
						}
					} else if ( face instanceof THREE.Face4 ) {
						v1 = _vertexPool[ face.a ];
						v2 = _vertexPool[ face.b ];
						v3 = _vertexPool[ face.c ];
						v4 = _vertexPool[ face.d ];
						_points4[ 0 ] = v1.positionScreen;
						_points4[ 1 ] = v2.positionScreen;
						_points4[ 2 ] = v3.positionScreen;
						_points4[ 3 ] = v4.positionScreen;
						if ( v1.visible === true || v2.visible === true || v3.visible === true || v4.visible === true ||
							_clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points4 ) ) ) {
							visible = ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
								( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ||
								( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) -
								( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0;
							if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
								_face = getNextFace4InPool();
								_face.id = object.id;
								_face.v1.copy( v1 );
								_face.v2.copy( v2 );
								_face.v3.copy( v3 );
								_face.v4.copy( v4 );
							} else {
								continue;
							}
						} else {
							continue;
						}
					}
					_face.normalModel.copy( face.normal );
					if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
						_face.normalModel.negate();
					}
					_face.normalModel.applyMatrix3( _normalMatrix ).normalize();
					_face.normalModelView.copy( _face.normalModel ).applyMatrix3( _normalViewMatrix );
					_face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix );
					faceVertexNormals = face.vertexNormals;
					for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) {
						var normalModel = _face.vertexNormalsModel[ n ];
						normalModel.copy( faceVertexNormals[ n ] );
						if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
							normalModel.negate();
						}
						normalModel.applyMatrix3( _normalMatrix ).normalize();
						var normalModelView = _face.vertexNormalsModelView[ n ];
						normalModelView.copy( normalModel ).applyMatrix3( _normalViewMatrix );
					}
					_face.vertexNormalsLength = faceVertexNormals.length;
					for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) {
						uvs = faceVertexUvs[ c ][ f ];
						if ( uvs === undefined ) continue;
						for ( u = 0, ul = uvs.length; u < ul; u ++ ) {
							_face.uvs[ c ][ u ] = uvs[ u ];
						}
					}
					_face.color = face.color;
					_face.material = material;
					_centroid.copy( _face.centroidModel ).applyProjection( _viewProjectionMatrix );
					_face.z = _centroid.z;
					_renderData.elements.push( _face );
				}
			} else if ( object instanceof THREE.Line ) {
				_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
				vertices = object.geometry.vertices;
				v1 = getNextVertexInPool();
				v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
								var step = object.type === THREE.LinePieces ? 2 : 1;
				for ( v = 1, vl = vertices.length; v < vl; v ++ ) {
					v1 = getNextVertexInPool();
					v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
					if ( ( v + 1 ) % step > 0 ) continue;
					v2 = _vertexPool[ _vertexCount - 2 ];
					_clippedVertex1PositionScreen.copy( v1.positionScreen );
					_clippedVertex2PositionScreen.copy( v2.positionScreen );
					if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
												_clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
						_clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
						_line = getNextLineInPool();
						_line.id = object.id;
						_line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
						_line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
						_line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
						_line.material = object.material;
						if ( object.material.vertexColors === THREE.VertexColors ) {
							_line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
							_line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
						}
						_renderData.elements.push( _line );
					}
				}
			}
		}
		for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) {
			object = _renderData.sprites[ o ].object;
			_modelMatrix = object.matrixWorld;
			if ( object instanceof THREE.Particle ) {
				_vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 );
				_vector4.applyMatrix4( _viewProjectionMatrix );
				var invW = 1 / _vector4.w;
				_vector4.z *= invW;
				if ( _vector4.z > 0 && _vector4.z < 1 ) {
					_particle = getNextParticleInPool();
					_particle.id = object.id;
					_particle.x = _vector4.x * invW;
					_particle.y = _vector4.y * invW;
					_particle.z = _vector4.z;
					_particle.object = object;
					_particle.rotation = object.rotation.z;
					_particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) );
					_particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) );
					_particle.material = object.material;
					_renderData.elements.push( _particle );
				}
			}
		}
		if ( sortElements === true ) _renderData.elements.sort( painterSort );
		return _renderData;
	};
		function getNextObjectInPool() {
		if ( _objectCount === _objectPoolLength ) {
			var object = new THREE.RenderableObject();
			_objectPool.push( object );
			_objectPoolLength ++;
			_objectCount ++;
			return object;
		}
		return _objectPool[ _objectCount ++ ];
	}
	function getNextVertexInPool() {
		if ( _vertexCount === _vertexPoolLength ) {
			var vertex = new THREE.RenderableVertex();
			_vertexPool.push( vertex );
			_vertexPoolLength ++;
			_vertexCount ++;
			return vertex;
		}
		return _vertexPool[ _vertexCount ++ ];
	}
	function getNextFace3InPool() {
		if ( _face3Count === _face3PoolLength ) {
			var face = new THREE.RenderableFace3();
			_face3Pool.push( face );
			_face3PoolLength ++;
			_face3Count ++;
			return face;
		}
		return _face3Pool[ _face3Count ++ ];
	}
	function getNextFace4InPool() {
		if ( _face4Count === _face4PoolLength ) {
			var face = new THREE.RenderableFace4();
			_face4Pool.push( face );
			_face4PoolLength ++;
			_face4Count ++;
			return face;
		}
		return _face4Pool[ _face4Count ++ ];
	}
	function getNextLineInPool() {
		if ( _lineCount === _linePoolLength ) {
			var line = new THREE.RenderableLine();
			_linePool.push( line );
			_linePoolLength ++;
			_lineCount ++
			return line;
		}
		return _linePool[ _lineCount ++ ];
	}
	function getNextParticleInPool() {
		if ( _particleCount === _particlePoolLength ) {
			var particle = new THREE.RenderableParticle();
			_particlePool.push( particle );
			_particlePoolLength ++;
			_particleCount ++
			return particle;
		}
		return _particlePool[ _particleCount ++ ];
	}
		function painterSort( a, b ) {
		if ( a.z !== b.z ) {
			return b.z - a.z;
		} else if ( a.id !== b.id ) {
			return a.id - b.id;
		} else {
			return 0;
		}
	}
	function clipLine( s1, s2 ) {
		var alpha1 = 0, alpha2 = 1,
						bc1near =  s1.z + s1.w,
		bc2near =  s2.z + s2.w,
		bc1far =  - s1.z + s1.w,
		bc2far =  - s2.z + s2.w;
		if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
						return true;
		} else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) {
						return false;
		} else {
						if ( bc1near < 0 ) {
								alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
			} else if ( bc2near < 0 ) {
								alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
			}
			if ( bc1far < 0 ) {
								alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
			} else if ( bc2far < 0 ) {
								alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
			}
			if ( alpha2 < alpha1 ) {
																return false;
			} else {
								s1.lerp( s2, alpha1 );
				s2.lerp( s1, 1 - alpha2 );
				return true;
			}
		}
	}
};
THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {
	this.a = a;
	this.b = b;
	this.c = c;
	this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
	this.vertexNormals = normal instanceof Array ? normal : [ ];
	this.color = color instanceof THREE.Color ? color : new THREE.Color();
	this.vertexColors = color instanceof Array ? color : [];
	this.vertexTangents = [];
	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
	this.centroid = new THREE.Vector3();
};
THREE.Face3.prototype = {
	constructor: THREE.Face3,
	clone: function () {
		var face = new THREE.Face3( this.a, this.b, this.c );
		face.normal.copy( this.normal );
		face.color.copy( this.color );
		face.centroid.copy( this.centroid );
		face.materialIndex = this.materialIndex;
		var i, il;
		for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
		for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
		for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
		return face;
	}
};
THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {
	this.a = a;
	this.b = b;
	this.c = c;
	this.d = d;
	this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
	this.vertexNormals = normal instanceof Array ? normal : [ ];
	this.color = color instanceof THREE.Color ? color : new THREE.Color();
	this.vertexColors = color instanceof Array ? color : [];
	this.vertexTangents = [];
	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
	this.centroid = new THREE.Vector3();
};
THREE.Face4.prototype = {
	constructor: THREE.Face4,
	clone: function () {
		var face = new THREE.Face4( this.a, this.b, this.c, this.d );
		face.normal.copy( this.normal );
		face.color.copy( this.color );
		face.centroid.copy( this.centroid );
		face.materialIndex = this.materialIndex;
		var i, il;
		for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
		for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
		for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
		return face;
	}
};
THREE.Geometry = function () {
	this.id = THREE.GeometryIdCount ++;
	this.uuid = THREE.Math.generateUUID();
	this.name = '';
	this.vertices = [];
	this.colors = [];  	this.normals = []; 	this.faces = [];
	this.faceUvs = [[]];
	this.faceVertexUvs = [[]];
	this.morphTargets = [];
	this.morphColors = [];
	this.morphNormals = [];
	this.skinWeights = [];
	this.skinIndices = [];
	this.lineDistances = [];
	this.boundingBox = null;
	this.boundingSphere = null;
	this.hasTangents = false;
	this.dynamic = true; 		this.verticesNeedUpdate = false;
	this.elementsNeedUpdate = false;
	this.uvsNeedUpdate = false;
	this.normalsNeedUpdate = false;
	this.tangentsNeedUpdate = false;
	this.colorsNeedUpdate = false;
	this.lineDistancesNeedUpdate = false;
	this.buffersNeedUpdate = false;
};
THREE.Geometry.prototype = {
	constructor: THREE.Geometry,
	applyMatrix: function ( matrix ) {
		var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
		for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
			var vertex = this.vertices[ i ];
			vertex.applyMatrix4( matrix );
		}
		for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
			var face = this.faces[ i ];
			face.normal.applyMatrix3( normalMatrix ).normalize();
			for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
				face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
			}
			face.centroid.applyMatrix4( matrix );
		}
		if ( this.boundingBox instanceof THREE.Box3 ) {
			this.computeBoundingBox();
		}
		if ( this.boundingSphere instanceof THREE.Sphere ) {
			this.computeBoundingSphere();
		}
	},
	computeCentroids: function () {
		var f, fl, face;
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
			face = this.faces[ f ];
			face.centroid.set( 0, 0, 0 );
			if ( face instanceof THREE.Face3 ) {
				face.centroid.add( this.vertices[ face.a ] );
				face.centroid.add( this.vertices[ face.b ] );
				face.centroid.add( this.vertices[ face.c ] );
				face.centroid.divideScalar( 3 );
			} else if ( face instanceof THREE.Face4 ) {
				face.centroid.add( this.vertices[ face.a ] );
				face.centroid.add( this.vertices[ face.b ] );
				face.centroid.add( this.vertices[ face.c ] );
				face.centroid.add( this.vertices[ face.d ] );
				face.centroid.divideScalar( 4 );
			}
		}
	},
	computeFaceNormals: function () {
		var cb = new THREE.Vector3(), ab = new THREE.Vector3();
		for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
			var face = this.faces[ f ];
			var vA = this.vertices[ face.a ];
			var vB = this.vertices[ face.b ];
			var vC = this.vertices[ face.c ];
			cb.subVectors( vC, vB );
			ab.subVectors( vA, vB );
			cb.cross( ab );
			cb.normalize();
			face.normal.copy( cb );
		}
	},
	computeVertexNormals: function ( areaWeighted ) {
		var v, vl, f, fl, face, vertices;
						if ( this.__tmpVertices === undefined ) {
			this.__tmpVertices = new Array( this.vertices.length );
			vertices = this.__tmpVertices;
			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
				vertices[ v ] = new THREE.Vector3();
			}
			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
				face = this.faces[ f ];
				if ( face instanceof THREE.Face3 ) {
					face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
				} else if ( face instanceof THREE.Face4 ) {
					face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
				}
			}
		} else {
			vertices = this.__tmpVertices;
			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
				vertices[ v ].set( 0, 0, 0 );
			}
		}
		if ( areaWeighted ) {
									var vA, vB, vC, vD;
			var cb = new THREE.Vector3(), ab = new THREE.Vector3(),
				db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3();
			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
				face = this.faces[ f ];
				if ( face instanceof THREE.Face3 ) {
					vA = this.vertices[ face.a ];
					vB = this.vertices[ face.b ];
					vC = this.vertices[ face.c ];
					cb.subVectors( vC, vB );
					ab.subVectors( vA, vB );
					cb.cross( ab );
					vertices[ face.a ].add( cb );
					vertices[ face.b ].add( cb );
					vertices[ face.c ].add( cb );
				} else if ( face instanceof THREE.Face4 ) {
					vA = this.vertices[ face.a ];
					vB = this.vertices[ face.b ];
					vC = this.vertices[ face.c ];
					vD = this.vertices[ face.d ];
										db.subVectors( vD, vB );
					ab.subVectors( vA, vB );
					db.cross( ab );
					vertices[ face.a ].add( db );
					vertices[ face.b ].add( db );
					vertices[ face.d ].add( db );
										dc.subVectors( vD, vC );
					bc.subVectors( vB, vC );
					dc.cross( bc );
					vertices[ face.b ].add( dc );
					vertices[ face.c ].add( dc );
					vertices[ face.d ].add( dc );
				}
			}
		} else {
			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
				face = this.faces[ f ];
				if ( face instanceof THREE.Face3 ) {
					vertices[ face.a ].add( face.normal );
					vertices[ face.b ].add( face.normal );
					vertices[ face.c ].add( face.normal );
				} else if ( face instanceof THREE.Face4 ) {
					vertices[ face.a ].add( face.normal );
					vertices[ face.b ].add( face.normal );
					vertices[ face.c ].add( face.normal );
					vertices[ face.d ].add( face.normal );
				}
			}
		}
		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
			vertices[ v ].normalize();
		}
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
			face = this.faces[ f ];
			if ( face instanceof THREE.Face3 ) {
				face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
				face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
				face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
			} else if ( face instanceof THREE.Face4 ) {
				face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
				face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
				face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
				face.vertexNormals[ 3 ].copy( vertices[ face.d ] );
			}
		}
	},
	computeMorphNormals: function () {
		var i, il, f, fl, face;
								for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
			face = this.faces[ f ];
			if ( ! face.__originalFaceNormal ) {
				face.__originalFaceNormal = face.normal.clone();
			} else {
				face.__originalFaceNormal.copy( face.normal );
			}
			if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
			for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
				if ( ! face.__originalVertexNormals[ i ] ) {
					face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
				} else {
					face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
				}
			}
		}
				var tmpGeo = new THREE.Geometry();
		tmpGeo.faces = this.faces;
		for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
						if ( ! this.morphNormals[ i ] ) {
				this.morphNormals[ i ] = {};
				this.morphNormals[ i ].faceNormals = [];
				this.morphNormals[ i ].vertexNormals = [];
				var dstNormalsFace = this.morphNormals[ i ].faceNormals;
				var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
				var faceNormal, vertexNormals;
				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
					face = this.faces[ f ];
					faceNormal = new THREE.Vector3();
					if ( face instanceof THREE.Face3 ) {
						vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
					} else {
						vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3(), d: new THREE.Vector3() };
					}
					dstNormalsFace.push( faceNormal );
					dstNormalsVertex.push( vertexNormals );
				}
			}
			var morphNormals = this.morphNormals[ i ];
						tmpGeo.vertices = this.morphTargets[ i ].vertices;
						tmpGeo.computeFaceNormals();
			tmpGeo.computeVertexNormals();
						var faceNormal, vertexNormals;
			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
				face = this.faces[ f ];
				faceNormal = morphNormals.faceNormals[ f ];
				vertexNormals = morphNormals.vertexNormals[ f ];
				faceNormal.copy( face.normal );
				if ( face instanceof THREE.Face3 ) {
					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
				} else {
					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
					vertexNormals.d.copy( face.vertexNormals[ 3 ] );
				}
			}
		}
				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
			face = this.faces[ f ];
			face.normal = face.__originalFaceNormal;
			face.vertexNormals = face.__originalVertexNormals;
		}
	},
	computeTangents: function () {
						var f, fl, v, vl, i, il, vertexIndex,
			face, uv, vA, vB, vC, uvA, uvB, uvC,
			x1, x2, y1, y2, z1, z2,
			s1, s2, t1, t2, r, t, test,
			tan1 = [], tan2 = [],
			sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
			tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
			n = new THREE.Vector3(), w;
		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
			tan1[ v ] = new THREE.Vector3();
			tan2[ v ] = new THREE.Vector3();
		}
		function handleTriangle( context, a, b, c, ua, ub, uc ) {
			vA = context.vertices[ a ];
			vB = context.vertices[ b ];
			vC = context.vertices[ c ];
			uvA = uv[ ua ];
			uvB = uv[ ub ];
			uvC = uv[ uc ];
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;
			s1 = uvB.x - uvA.x;
			s2 = uvC.x - uvA.x;
			t1 = uvB.y - uvA.y;
			t2 = uvC.y - uvA.y;
			r = 1.0 / ( s1 * t2 - s2 * t1 );
			sdir.set( ( t2 * x1 - t1 * x2 ) * r,
					  ( t2 * y1 - t1 * y2 ) * r,
					  ( t2 * z1 - t1 * z2 ) * r );
			tdir.set( ( s1 * x2 - s2 * x1 ) * r,
					  ( s1 * y2 - s2 * y1 ) * r,
					  ( s1 * z2 - s2 * z1 ) * r );
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
		}
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
			face = this.faces[ f ];
			uv = this.faceVertexUvs[ 0 ][ f ]; 			if ( face instanceof THREE.Face3 ) {
				handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
			} else if ( face instanceof THREE.Face4 ) {
				handleTriangle( this, face.a, face.b, face.d, 0, 1, 3 );
				handleTriangle( this, face.b, face.c, face.d, 1, 2, 3 );
			}
		}
		var faceIndex = [ 'a', 'b', 'c', 'd' ];
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
			face = this.faces[ f ];
			for ( i = 0; i < face.vertexNormals.length; i++ ) {
				n.copy( face.vertexNormals[ i ] );
				vertexIndex = face[ faceIndex[ i ] ];
				t = tan1[ vertexIndex ];
								tmp.copy( t );
				tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
								tmp2.crossVectors( face.vertexNormals[ i ], t );
				test = tmp2.dot( tan2[ vertexIndex ] );
				w = (test < 0.0) ? -1.0 : 1.0;
				face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );
			}
		}
		this.hasTangents = true;
	},
	computeLineDistances: function ( ) {
		var d = 0;
		var vertices = this.vertices;
		for ( var i = 0, il = vertices.length; i < il; i ++ ) {
			if ( i > 0 ) {
				d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
			}
			this.lineDistances[ i ] = d;
		}
	},
	computeBoundingBox: function () {
		if ( this.boundingBox === null ) {
			this.boundingBox = new THREE.Box3();
		}
		this.boundingBox.setFromPoints( this.vertices );
	},
	computeBoundingSphere: function () {
		if ( this.boundingSphere === null ) {
			this.boundingSphere = new THREE.Sphere();
		}
		this.boundingSphere.setFromPoints( this.vertices );
	},
	/*
	 * Checks for duplicate vertices with hashmap.
	 * Duplicated vertices are removed
	 * and faces' vertices are updated.
	 */
	mergeVertices: function () {
		var verticesMap = {}; 		var unique = [], changes = [];
		var v, key;
		var precisionPoints = 4; 		var precision = Math.pow( 10, precisionPoints );
		var i,il, face;
		var indices, k, j, jl, u;
				this.__tmpVertices = undefined;
		for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
			v = this.vertices[ i ];
			key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
			if ( verticesMap[ key ] === undefined ) {
				verticesMap[ key ] = i;
				unique.push( this.vertices[ i ] );
				changes[ i ] = unique.length - 1;
			} else {
								changes[ i ] = changes[ verticesMap[ key ] ];
			}
		};
						var faceIndicesToRemove = [];
		for( i = 0, il = this.faces.length; i < il; i ++ ) {
			face = this.faces[ i ];
			if ( face instanceof THREE.Face3 ) {
				face.a = changes[ face.a ];
				face.b = changes[ face.b ];
				face.c = changes[ face.c ];
				indices = [ face.a, face.b, face.c ];
				var dupIndex = -1;
												for ( var n = 0; n < 3; n ++ ) {
					if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) {
						dupIndex = n;
						faceIndicesToRemove.push( i );
						break;
					}
				}
			} else if ( face instanceof THREE.Face4 ) {
				face.a = changes[ face.a ];
				face.b = changes[ face.b ];
				face.c = changes[ face.c ];
				face.d = changes[ face.d ];
								indices = [ face.a, face.b, face.c, face.d ];
				var dupIndex = -1;
				for ( var n = 0; n < 4; n ++ ) {
					if ( indices[ n ] == indices[ ( n + 1 ) % 4 ] ) {
																								if ( dupIndex >= 0 ) {
							faceIndicesToRemove.push( i );
						}
						dupIndex = n;
					}
				}
				if ( dupIndex >= 0 ) {
					indices.splice( dupIndex, 1 );
					var newFace = new THREE.Face3( indices[0], indices[1], indices[2], face.normal, face.color, face.materialIndex );
					for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
						u = this.faceVertexUvs[ j ][ i ];
						if ( u ) {
							u.splice( dupIndex, 1 );
						}
					}
					if( face.vertexNormals && face.vertexNormals.length > 0) {
						newFace.vertexNormals = face.vertexNormals;
						newFace.vertexNormals.splice( dupIndex, 1 );
					}
					if( face.vertexColors && face.vertexColors.length > 0 ) {
						newFace.vertexColors = face.vertexColors;
						newFace.vertexColors.splice( dupIndex, 1 );
					}
					this.faces[ i ] = newFace;
				}
			}
		}
		for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
			this.faces.splice( i, 1 );
			for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
				this.faceVertexUvs[ j ].splice( i, 1 );
			}
		}
				var diff = this.vertices.length - unique.length;
		this.vertices = unique;
		return diff;
	},
	clone: function () {
		var geometry = new THREE.Geometry();
		var vertices = this.vertices;
		for ( var i = 0, il = vertices.length; i < il; i ++ ) {
			geometry.vertices.push( vertices[ i ].clone() );
		}
		var faces = this.faces;
		for ( var i = 0, il = faces.length; i < il; i ++ ) {
			geometry.faces.push( faces[ i ].clone() );
		}
		var uvs = this.faceVertexUvs[ 0 ];
		for ( var i = 0, il = uvs.length; i < il; i ++ ) {
			var uv = uvs[ i ], uvCopy = [];
			for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
				uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
			}
			geometry.faceVertexUvs[ 0 ].push( uvCopy );
		}
		return geometry;
	},
	dispose: function () {
		this.dispatchEvent( { type: 'dispose' } );
	}
};
THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype );
THREE.GeometryIdCount = 0;
THREE.BufferGeometry = function () {
	this.id = THREE.GeometryIdCount ++;
	this.uuid = THREE.Math.generateUUID();
		this.attributes = {};
		this.dynamic = false;
		this.offsets = [];
		this.boundingBox = null;
	this.boundingSphere = null;
	this.hasTangents = false;
		this.morphTargets = [];
};
THREE.BufferGeometry.prototype = {
	constructor: THREE.BufferGeometry,
	applyMatrix: function ( matrix ) {
		var positionArray;
		var normalArray;
		if ( this.attributes[ "position" ] ) positionArray = this.attributes[ "position" ].array;
		if ( this.attributes[ "normal" ] ) normalArray = this.attributes[ "normal" ].array;
		if ( positionArray !== undefined ) {
			matrix.multiplyVector3Array( positionArray );
			this.verticesNeedUpdate = true;
		}
		if ( normalArray !== undefined ) {
			var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
			normalMatrix.multiplyVector3Array( normalArray );
			this.normalizeNormals();
			this.normalsNeedUpdate = true;
		}
	},
	computeBoundingBox: function () {
		if ( this.boundingBox === null ) {
			this.boundingBox = new THREE.Box3();
		}
		var positions = this.attributes[ "position" ].array;
		if ( positions ) {
			var bb = this.boundingBox;
			var x, y, z;
			if( positions.length >= 3 ) {
				bb.min.x = bb.max.x = positions[ 0 ];
				bb.min.y = bb.max.y = positions[ 1 ];
				bb.min.z = bb.max.z = positions[ 2 ];
			}
			for ( var i = 3, il = positions.length; i < il; i += 3 ) {
				x = positions[ i ];
				y = positions[ i + 1 ];
				z = positions[ i + 2 ];
								if ( x < bb.min.x ) {
					bb.min.x = x;
				} else if ( x > bb.max.x ) {
					bb.max.x = x;
				}
				if ( y < bb.min.y ) {
					bb.min.y = y;
				} else if ( y > bb.max.y ) {
					bb.max.y = y;
				}
				if ( z < bb.min.z ) {
					bb.min.z = z;
				} else if ( z > bb.max.z ) {
					bb.max.z = z;
				}
			}
		}
		if ( positions === undefined || positions.length === 0 ) {
			this.boundingBox.min.set( 0, 0, 0 );
			this.boundingBox.max.set( 0, 0, 0 );
		}
	},
	computeBoundingSphere: function () {
		if ( this.boundingSphere === null ) {
			this.boundingSphere = new THREE.Sphere();
		}
		var positions = this.attributes[ "position" ].array;
		if ( positions ) {
			var radiusSq, maxRadiusSq = 0;
			var x, y, z;
			for ( var i = 0, il = positions.length; i < il; i += 3 ) {
				x = positions[ i ];
				y = positions[ i + 1 ];
				z = positions[ i + 2 ];
				radiusSq =  x * x + y * y + z * z;
				if ( radiusSq > maxRadiusSq ) maxRadiusSq = radiusSq;
			}
			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
		}
	},
	computeVertexNormals: function () {
		if ( this.attributes[ "position" ] ) {
			var i, il;
			var j, jl;
			var nVertexElements = this.attributes[ "position" ].array.length;
			if ( this.attributes[ "normal" ] === undefined ) {
				this.attributes[ "normal" ] = {
					itemSize: 3,
					array: new Float32Array( nVertexElements )
				};
			} else {
								for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) {
					this.attributes[ "normal" ].array[ i ] = 0;
				}
			}
			var positions = this.attributes[ "position" ].array;
			var normals = this.attributes[ "normal" ].array;
			var vA, vB, vC, x, y, z,
			pA = new THREE.Vector3(),
			pB = new THREE.Vector3(),
			pC = new THREE.Vector3(),
			cb = new THREE.Vector3(),
			ab = new THREE.Vector3();
						if ( this.attributes[ "index" ] ) {
				var indices = this.attributes[ "index" ].array;
				var offsets = this.offsets;
				for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
					var start = offsets[ j ].start;
					var count = offsets[ j ].count;
					var index = offsets[ j ].index;
					for ( i = start, il = start + count; i < il; i += 3 ) {
						vA = index + indices[ i ];
						vB = index + indices[ i + 1 ];
						vC = index + indices[ i + 2 ];
						x = positions[ vA * 3 ];
						y = positions[ vA * 3 + 1 ];
						z = positions[ vA * 3 + 2 ];
						pA.set( x, y, z );
						x = positions[ vB * 3 ];
						y = positions[ vB * 3 + 1 ];
						z = positions[ vB * 3 + 2 ];
						pB.set( x, y, z );
						x = positions[ vC * 3 ];
						y = positions[ vC * 3 + 1 ];
						z = positions[ vC * 3 + 2 ];
						pC.set( x, y, z );
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
						normals[ vA * 3 ]     += cb.x;
						normals[ vA * 3 + 1 ] += cb.y;
						normals[ vA * 3 + 2 ] += cb.z;
						normals[ vB * 3 ]     += cb.x;
						normals[ vB * 3 + 1 ] += cb.y;
						normals[ vB * 3 + 2 ] += cb.z;
						normals[ vC * 3 ]     += cb.x;
						normals[ vC * 3 + 1 ] += cb.y;
						normals[ vC * 3 + 2 ] += cb.z;
					}
				}
						} else {
				for ( i = 0, il = positions.length; i < il; i += 9 ) {
					x = positions[ i ];
					y = positions[ i + 1 ];
					z = positions[ i + 2 ];
					pA.set( x, y, z );
					x = positions[ i + 3 ];
					y = positions[ i + 4 ];
					z = positions[ i + 5 ];
					pB.set( x, y, z );
					x = positions[ i + 6 ];
					y = positions[ i + 7 ];
					z = positions[ i + 8 ];
					pC.set( x, y, z );
					cb.subVectors( pC, pB );
					ab.subVectors( pA, pB );
					cb.cross( ab );
					normals[ i ] 	 = cb.x;
					normals[ i + 1 ] = cb.y;
					normals[ i + 2 ] = cb.z;
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
				}
			}
			this.normalizeNormals();
			this.normalsNeedUpdate = true;
		}
	},
	normalizeNormals: function () {
		var normals = this.attributes[ "normal" ].array;
		var x, y, z, n;
		for ( var i = 0, il = normals.length; i < il; i += 3 ) {
			x = normals[ i ];
			y = normals[ i + 1 ];
			z = normals[ i + 2 ];
			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
			normals[ i ] 	 *= n;
			normals[ i + 1 ] *= n;
			normals[ i + 2 ] *= n;
		}
	},
	computeTangents: function () {
						if ( this.attributes[ "index" ] === undefined ||
			 this.attributes[ "position" ] === undefined ||
			 this.attributes[ "normal" ] === undefined ||
			 this.attributes[ "uv" ] === undefined ) {
			console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" );
			return;
		}
		var indices = this.attributes[ "index" ].array;
		var positions = this.attributes[ "position" ].array;
		var normals = this.attributes[ "normal" ].array;
		var uvs = this.attributes[ "uv" ].array;
		var nVertices = positions.length / 3;
		if ( this.attributes[ "tangent" ] === undefined ) {
			var nTangentElements = 4 * nVertices;
			this.attributes[ "tangent" ] = {
				itemSize: 4,
				array: new Float32Array( nTangentElements )
			};
		}
		var tangents = this.attributes[ "tangent" ].array;
		var tan1 = [], tan2 = [];
		for ( var k = 0; k < nVertices; k ++ ) {
			tan1[ k ] = new THREE.Vector3();
			tan2[ k ] = new THREE.Vector3();
		}
		var xA, yA, zA,
			xB, yB, zB,
			xC, yC, zC,
			uA, vA,
			uB, vB,
			uC, vC,
			x1, x2, y1, y2, z1, z2,
			s1, s2, t1, t2, r;
		var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
		function handleTriangle( a, b, c ) {
			xA = positions[ a * 3 ];
			yA = positions[ a * 3 + 1 ];
			zA = positions[ a * 3 + 2 ];
			xB = positions[ b * 3 ];
			yB = positions[ b * 3 + 1 ];
			zB = positions[ b * 3 + 2 ];
			xC = positions[ c * 3 ];
			yC = positions[ c * 3 + 1 ];
			zC = positions[ c * 3 + 2 ];
			uA = uvs[ a * 2 ];
			vA = uvs[ a * 2 + 1 ];
			uB = uvs[ b * 2 ];
			vB = uvs[ b * 2 + 1 ];
			uC = uvs[ c * 2 ];
			vC = uvs[ c * 2 + 1 ];
			x1 = xB - xA;
			x2 = xC - xA;
			y1 = yB - yA;
			y2 = yC - yA;
			z1 = zB - zA;
			z2 = zC - zA;
			s1 = uB - uA;
			s2 = uC - uA;
			t1 = vB - vA;
			t2 = vC - vA;
			r = 1.0 / ( s1 * t2 - s2 * t1 );
			sdir.set(
				( t2 * x1 - t1 * x2 ) * r,
				( t2 * y1 - t1 * y2 ) * r,
				( t2 * z1 - t1 * z2 ) * r
			);
			tdir.set(
				( s1 * x2 - s2 * x1 ) * r,
				( s1 * y2 - s2 * y1 ) * r,
				( s1 * z2 - s2 * z1 ) * r
			);
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
		}
		var i, il;
		var j, jl;
		var iA, iB, iC;
		var offsets = this.offsets;
		for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
			var start = offsets[ j ].start;
			var count = offsets[ j ].count;
			var index = offsets[ j ].index;
			for ( i = start, il = start + count; i < il; i += 3 ) {
				iA = index + indices[ i ];
				iB = index + indices[ i + 1 ];
				iC = index + indices[ i + 2 ];
				handleTriangle( iA, iB, iC );
			}
		}
		var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
		var n = new THREE.Vector3(), n2 = new THREE.Vector3();
		var w, t, test;
		function handleVertex( v ) {
			n.x = normals[ v * 3 ];
			n.y = normals[ v * 3 + 1 ];
			n.z = normals[ v * 3 + 2 ];
			n2.copy( n );
			t = tan1[ v ];
						tmp.copy( t );
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
						tmp2.crossVectors( n2, t );
			test = tmp2.dot( tan2[ v ] );
			w = ( test < 0.0 ) ? -1.0 : 1.0;
			tangents[ v * 4 ]     = tmp.x;
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;
		}
		for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
			var start = offsets[ j ].start;
			var count = offsets[ j ].count;
			var index = offsets[ j ].index;
			for ( i = start, il = start + count; i < il; i += 3 ) {
				iA = index + indices[ i ];
				iB = index + indices[ i + 1 ];
				iC = index + indices[ i + 2 ];
				handleVertex( iA );
				handleVertex( iB );
				handleVertex( iC );
			}
		}
		this.hasTangents = true;
		this.tangentsNeedUpdate = true;
	},
	dispose: function () {
		this.dispatchEvent( { type: 'dispose' } );
	}
};
THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );
THREE.Camera = function () {
	THREE.Object3D.call( this );
	this.matrixWorldInverse = new THREE.Matrix4();
	this.projectionMatrix = new THREE.Matrix4();
	this.projectionMatrixInverse = new THREE.Matrix4();
};
THREE.Camera.prototype = Object.create( THREE.Object3D.prototype );
THREE.Camera.prototype.lookAt = function () {
		var m1 = new THREE.Matrix4();
	return function ( vector ) {
		m1.lookAt( this.position, vector, this.up );
		this.quaternion.setFromRotationMatrix( m1 );
	};
}();
THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {
	THREE.Camera.call( this );
	this.fov = fov !== undefined ? fov : 50;
	this.aspect = aspect !== undefined ? aspect : 1;
	this.near = near !== undefined ? near : 0.1;
	this.far = far !== undefined ? far : 2000;
	this.updateProjectionMatrix();
};
THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );
THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {
	if ( frameHeight === undefined ) frameHeight = 24;
	this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
	this.updateProjectionMatrix();
}
THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {
	this.fullWidth = fullWidth;
	this.fullHeight = fullHeight;
	this.x = x;
	this.y = y;
	this.width = width;
	this.height = height;
	this.updateProjectionMatrix();
};
THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {
	if ( this.fullWidth ) {
		var aspect = this.fullWidth / this.fullHeight;
		var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near;
		var bottom = -top;
		var left = aspect * bottom;
		var right = aspect * top;
		var width = Math.abs( right - left );
		var height = Math.abs( top - bottom );
		this.projectionMatrix.makeFrustum(
			left + this.x * width / this.fullWidth,
			left + ( this.x + this.width ) * width / this.fullWidth,
			top - ( this.y + this.height ) * height / this.fullHeight,
			top - this.y * height / this.fullHeight,
			this.near,
			this.far
		);
	} else {
		this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far );
	}
};
THREE.Light = function ( hex ) {
	THREE.Object3D.call( this );
	this.color = new THREE.Color( hex );
};
THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
THREE.Light.prototype.clone = function ( light ) {
	if ( light === undefined ) light = new THREE.Light();
	THREE.Object3D.prototype.clone.call( this, light );
	light.color.copy( this.color );
	return light;
};
THREE.AmbientLight = function ( hex ) {
	THREE.Light.call( this, hex );
};
THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
THREE.AmbientLight.prototype.clone = function () {
	var light = new THREE.AmbientLight();
	THREE.Light.prototype.clone.call( this, light );
	return light;
};
THREE.AreaLight = function ( hex, intensity ) {
	THREE.Light.call( this, hex );
	this.normal = new THREE.Vector3( 0, -1, 0 );
	this.right = new THREE.Vector3( 1, 0, 0 );
	this.intensity = ( intensity !== undefined ) ? intensity : 1;
	this.width = 1.0;
	this.height = 1.0;
	this.constantAttenuation = 1.5;
	this.linearAttenuation = 0.5;
	this.quadraticAttenuation = 0.1;
};
THREE.AreaLight.prototype = Object.create( THREE.Light.prototype );
THREE.DirectionalLight = function ( hex, intensity ) {
	THREE.Light.call( this, hex );
	this.position.set( 0, 1, 0 );
	this.target = new THREE.Object3D();
	this.intensity = ( intensity !== undefined ) ? intensity : 1;
	this.castShadow = false;
	this.onlyShadow = false;
		this.shadowCameraNear = 50;
	this.shadowCameraFar = 5000;
	this.shadowCameraLeft = -500;
	this.shadowCameraRight = 500;
	this.shadowCameraTop = 500;
	this.shadowCameraBottom = -500;
	this.shadowCameraVisible = false;
	this.shadowBias = 0;
	this.shadowDarkness = 0.5;
	this.shadowMapWidth = 512;
	this.shadowMapHeight = 512;
		this.shadowCascade = false;
	this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 );
	this.shadowCascadeCount = 2;
	this.shadowCascadeBias = [ 0, 0, 0 ];
	this.shadowCascadeWidth = [ 512, 512, 512 ];
	this.shadowCascadeHeight = [ 512, 512, 512 ];
	this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ];
	this.shadowCascadeFarZ  = [  0.990, 0.998, 1.000 ];
	this.shadowCascadeArray = [];
		this.shadowMap = null;
	this.shadowMapSize = null;
	this.shadowCamera = null;
	this.shadowMatrix = null;
};
THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype );
THREE.DirectionalLight.prototype.clone = function () {
	var light = new THREE.DirectionalLight();
	THREE.Light.prototype.clone.call( this, light );
	light.target = this.target.clone();
	light.intensity = this.intensity;
	light.castShadow = this.castShadow;
	light.onlyShadow = this.onlyShadow;
	return light;
};
THREE.HemisphereLight = function ( skyColorHex, groundColorHex, intensity ) {
	THREE.Light.call( this, skyColorHex );
	this.position.set( 0, 100, 0 );
	this.groundColor = new THREE.Color( groundColorHex );
	this.intensity = ( intensity !== undefined ) ? intensity : 1;
};
THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );
THREE.HemisphereLight.prototype.clone = function () {
	var light = new THREE.PointLight();
	THREE.Light.prototype.clone.call( this, light );
	light.groundColor.copy( this.groundColor );
	light.intensity = this.intensity;
	return light;
};
THREE.PointLight = function ( hex, intensity, distance ) {
	THREE.Light.call( this, hex );
	this.intensity = ( intensity !== undefined ) ? intensity : 1;
	this.distance = ( distance !== undefined ) ? distance : 0;
};
THREE.PointLight.prototype = Object.create( THREE.Light.prototype );
THREE.PointLight.prototype.clone = function () {
	var light = new THREE.PointLight();
	THREE.Light.prototype.clone.call( this, light );
	light.intensity = this.intensity;
	light.distance = this.distance;
	return light;
};
THREE.SpotLight = function ( hex, intensity, distance, angle, exponent ) {
	THREE.Light.call( this, hex );
	this.position.set( 0, 1, 0 );
	this.target = new THREE.Object3D();
	this.intensity = ( intensity !== undefined ) ? intensity : 1;
	this.distance = ( distance !== undefined ) ? distance : 0;
	this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
	this.exponent = ( exponent !== undefined ) ? exponent : 10;
	this.castShadow = false;
	this.onlyShadow = false;
		this.shadowCameraNear = 50;
	this.shadowCameraFar = 5000;
	this.shadowCameraFov = 50;
	this.shadowCameraVisible = false;
	this.shadowBias = 0;
	this.shadowDarkness = 0.5;
	this.shadowMapWidth = 512;
	this.shadowMapHeight = 512;
		this.shadowMap = null;
	this.shadowMapSize = null;
	this.shadowCamera = null;
	this.shadowMatrix = null;
};
THREE.SpotLight.prototype = Object.create( THREE.Light.prototype );
THREE.SpotLight.prototype.clone = function () {
	var light = new THREE.SpotLight();
	THREE.Light.prototype.clone.call( this, light );
	light.target = this.target.clone();
	light.intensity = this.intensity;
	light.distance = this.distance;
	light.angle = this.angle;
	light.exponent = this.exponent;
	light.castShadow = this.castShadow;
	light.onlyShadow = this.onlyShadow;
	return light;
};
THREE.ImageLoader = function ( manager ) {
	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.ImageLoader.prototype = {
	constructor: THREE.ImageLoader,
	load: function ( url, onLoad, onProgress, onError ) {
		var scope = this;
		var image = document.createElement( 'img' );
		if ( onLoad !== undefined ) {
			image.addEventListener( 'load', function ( event ) {
				scope.manager.itemEnd( url );
				onLoad( this );
			}, false );
		}
		if ( onProgress !== undefined ) {
			image.addEventListener( 'progress', function ( event ) {
				onProgress( event );
			}, false );
		}
		if ( onError !== undefined ) {
			image.addEventListener( 'error', function ( event ) {
				onError( event );
			}, false );
		}
		if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
		image.src = url;
		scope.manager.itemStart( url );
	},
	setCrossOrigin: function ( value ) {
		this.crossOrigin = value;
	}
}
THREE.LoadingManager = function ( onLoad, onProgress, onError ) {
	var scope = this;
	var loaded = 0, total = 0;
	this.onLoad = onLoad;
	this.onProgress = onProgress;
	this.onError = onError;
	this.itemStart = function ( url ) {
		total ++;
	};
	this.itemEnd = function ( url ) {
		loaded ++;
		if ( scope.onProgress !== undefined ) {
			scope.onProgress( url, loaded, total );
		}
		if ( loaded === total && scope.onLoad !== undefined ) {
			scope.onLoad();
		}
	};
};
THREE.DefaultLoadingManager = new THREE.LoadingManager();
THREE.Material = function () {
	this.id = THREE.MaterialIdCount ++;
	this.uuid = THREE.Math.generateUUID();
	this.name = '';
	this.side = THREE.FrontSide;
	this.opacity = 1;
	this.transparent = false;
	this.blending = THREE.NormalBlending;
	this.blendSrc = THREE.SrcAlphaFactor;
	this.blendDst = THREE.OneMinusSrcAlphaFactor;
	this.blendEquation = THREE.AddEquation;
	this.depthTest = true;
	this.depthWrite = true;
	this.polygonOffset = false;
	this.polygonOffsetFactor = 0;
	this.polygonOffsetUnits = 0;
	this.alphaTest = 0;
	this.overdraw = 0; 	this.visible = true;
	this.needsUpdate = true;
};
THREE.Material.prototype = {
	constructor: THREE.Material,
	setValues: function ( values ) {
		if ( values === undefined ) return;
		for ( var key in values ) {
			var newValue = values[ key ];
			if ( newValue === undefined ) {
				console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
				continue;
			}
			if ( key in this ) {
				var currentValue = this[ key ];
				if ( currentValue instanceof THREE.Color ) {
					currentValue.set( newValue );
				} else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {
					currentValue.copy( newValue );
				} else if ( key == 'overdraw') {
										this[ key ] = Number(newValue);
				} else {
					this[ key ] = newValue;
				}
			}
		}
	},
	clone: function ( material ) {
		if ( material === undefined ) material = new THREE.Material();
		material.name = this.name;
		material.side = this.side;
		material.opacity = this.opacity;
		material.transparent = this.transparent;
		material.blending = this.blending;
		material.blendSrc = this.blendSrc;
		material.blendDst = this.blendDst;
		material.blendEquation = this.blendEquation;
		material.depthTest = this.depthTest;
		material.depthWrite = this.depthWrite;
		material.polygonOffset = this.polygonOffset;
		material.polygonOffsetFactor = this.polygonOffsetFactor;
		material.polygonOffsetUnits = this.polygonOffsetUnits;
		material.alphaTest = this.alphaTest;
		material.overdraw = this.overdraw;
		material.visible = this.visible;
		return material;
	},
	dispose: function () {
		this.dispatchEvent( { type: 'dispose' } );
	}
};
THREE.EventDispatcher.prototype.apply( THREE.Material.prototype );
THREE.MaterialIdCount = 0;
THREE.MeshBasicMaterial = function ( parameters ) {
	THREE.Material.call( this );
	this.color = new THREE.Color( 0xffffff ); 	this.map = null;
	this.lightMap = null;
	this.specularMap = null;
	this.envMap = null;
	this.combine = THREE.MultiplyOperation;
	this.reflectivity = 1;
	this.refractionRatio = 0.98;
	this.fog = true;
	this.shading = THREE.SmoothShading;
	this.wireframe = false;
	this.wireframeLinewidth = 1;
	this.wireframeLinecap = 'round';
	this.wireframeLinejoin = 'round';
	this.vertexColors = THREE.NoColors;
	this.skinning = false;
	this.morphTargets = false;
	this.setValues( parameters );
};
THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.MeshBasicMaterial.prototype.clone = function () {
	var material = new THREE.MeshBasicMaterial();
	THREE.Material.prototype.clone.call( this, material );
	material.color.copy( this.color );
	material.map = this.map;
	material.lightMap = this.lightMap;
	material.specularMap = this.specularMap;
	material.envMap = this.envMap;
	material.combine = this.combine;
	material.reflectivity = this.reflectivity;
	material.refractionRatio = this.refractionRatio;
	material.fog = this.fog;
	material.shading = this.shading;
	material.wireframe = this.wireframe;
	material.wireframeLinewidth = this.wireframeLinewidth;
	material.wireframeLinecap = this.wireframeLinecap;
	material.wireframeLinejoin = this.wireframeLinejoin;
	material.vertexColors = this.vertexColors;
	material.skinning = this.skinning;
	material.morphTargets = this.morphTargets;
	return material;
};
THREE.MeshLambertMaterial = function ( parameters ) {
	THREE.Material.call( this );
	this.color = new THREE.Color( 0xffffff ); 	this.ambient = new THREE.Color( 0xffffff );
	this.emissive = new THREE.Color( 0x000000 );
	this.wrapAround = false;
	this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
	this.map = null;
	this.lightMap = null;
	this.specularMap = null;
	this.envMap = null;
	this.combine = THREE.MultiplyOperation;
	this.reflectivity = 1;
	this.refractionRatio = 0.98;
	this.fog = true;
	this.shading = THREE.SmoothShading;
	this.wireframe = false;
	this.wireframeLinewidth = 1;
	this.wireframeLinecap = 'round';
	this.wireframeLinejoin = 'round';
	this.vertexColors = THREE.NoColors;
	this.skinning = false;
	this.morphTargets = false;
	this.morphNormals = false;
	this.setValues( parameters );
};
THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.MeshLambertMaterial.prototype.clone = function () {
	var material = new THREE.MeshLambertMaterial();
	THREE.Material.prototype.clone.call( this, material );
	material.color.copy( this.color );
	material.ambient.copy( this.ambient );
	material.emissive.copy( this.emissive );
	material.wrapAround = this.wrapAround;
	material.wrapRGB.copy( this.wrapRGB );
	material.map = this.map;
	material.lightMap = this.lightMap;
	material.specularMap = this.specularMap;
	material.envMap = this.envMap;
	material.combine = this.combine;
	material.reflectivity = this.reflectivity;
	material.refractionRatio = this.refractionRatio;
	material.fog = this.fog;
	material.shading = this.shading;
	material.wireframe = this.wireframe;
	material.wireframeLinewidth = this.wireframeLinewidth;
	material.wireframeLinecap = this.wireframeLinecap;
	material.wireframeLinejoin = this.wireframeLinejoin;
	material.vertexColors = this.vertexColors;
	material.skinning = this.skinning;
	material.morphTargets = this.morphTargets;
	material.morphNormals = this.morphNormals;
	return material;
};
THREE.MeshFaceMaterial = function ( materials ) {
	this.materials = materials instanceof Array ? materials : [];
};
THREE.MeshFaceMaterial.prototype.clone = function () {
	return new THREE.MeshFaceMaterial( this.materials.slice( 0 ) );
};
THREE.ShaderMaterial = function ( parameters ) {
	THREE.Material.call( this );
	this.fragmentShader = "void main() {}";
	this.vertexShader = "void main() {}";
	this.uniforms = {};
	this.defines = {};
	this.attributes = null;
	this.shading = THREE.SmoothShading;
	this.linewidth = 1;
	this.wireframe = false;
	this.wireframeLinewidth = 1;
	this.fog = false; 	this.lights = false; 	this.vertexColors = THREE.NoColors; 	this.skinning = false; 	this.morphTargets = false; 	this.morphNormals = false; 	this.setValues( parameters );
};
THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.ShaderMaterial.prototype.clone = function () {
	var material = new THREE.ShaderMaterial();
	THREE.Material.prototype.clone.call( this, material );
	material.fragmentShader = this.fragmentShader;
	material.vertexShader = this.vertexShader;
	material.uniforms = THREE.UniformsUtils.clone( this.uniforms );
	material.attributes = this.attributes;
	material.defines = this.defines;
	material.shading = this.shading;
	material.wireframe = this.wireframe;
	material.wireframeLinewidth = this.wireframeLinewidth;
	material.fog = this.fog;
	material.lights = this.lights;
	material.vertexColors = this.vertexColors;
	material.skinning = this.skinning;
	material.morphTargets = this.morphTargets;
	material.morphNormals = this.morphNormals;
	return material;
};
THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
	this.id = THREE.TextureIdCount ++;
	this.uuid = THREE.Math.generateUUID();
	this.name = '';
	this.image = image;
	this.mipmaps = [];
	this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping();
	this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping;
	this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;
	this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;
	this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter;
	this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
	this.format = format !== undefined ? format : THREE.RGBAFormat;
	this.type = type !== undefined ? type : THREE.UnsignedByteType;
	this.offset = new THREE.Vector2( 0, 0 );
	this.repeat = new THREE.Vector2( 1, 1 );
	this.generateMipmaps = true;
	this.premultiplyAlpha = false;
	this.flipY = true;
	this.unpackAlignment = 4; 	this.needsUpdate = false;
	this.onUpdate = null;
};
THREE.Texture.prototype = {
	constructor: THREE.Texture,
	clone: function ( texture ) {
		if ( texture === undefined ) texture = new THREE.Texture();
		texture.image = this.image;
		texture.mipmaps = this.mipmaps.slice(0);
		texture.mapping = this.mapping;
		texture.wrapS = this.wrapS;
		texture.wrapT = this.wrapT;
		texture.magFilter = this.magFilter;
		texture.minFilter = this.minFilter;
		texture.anisotropy = this.anisotropy;
		texture.format = this.format;
		texture.type = this.type;
		texture.offset.copy( this.offset );
		texture.repeat.copy( this.repeat );
		texture.generateMipmaps = this.generateMipmaps;
		texture.premultiplyAlpha = this.premultiplyAlpha;
		texture.flipY = this.flipY;
		texture.unpackAlignment = this.unpackAlignment;
		return texture;
	},
	dispose: function () {
		this.dispatchEvent( { type: 'dispose' } );
	}
};
THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype );
THREE.TextureIdCount = 0;
THREE.Mesh = function ( geometry, material ) {
	THREE.Object3D.call( this );
	this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
	this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );
	this.updateMorphTargets();
};
THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
THREE.Mesh.prototype.updateMorphTargets = function () {
	if ( this.geometry.morphTargets.length > 0 ) {
		this.morphTargetBase = -1;
		this.morphTargetForcedOrder = [];
		this.morphTargetInfluences = [];
		this.morphTargetDictionary = {};
		for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {
			this.morphTargetInfluences.push( 0 );
			this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;
		}
	}
};
THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {
	if ( this.morphTargetDictionary[ name ] !== undefined ) {
		return this.morphTargetDictionary[ name ];
	}
	console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." );
	return 0;
};
THREE.Mesh.prototype.clone = function ( object ) {
	if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );
	THREE.Object3D.prototype.clone.call( this, object );
	return object;
};
THREE.Bone = function( belongsToSkin ) {
	THREE.Object3D.call( this );
	this.skin = belongsToSkin;
	this.skinMatrix = new THREE.Matrix4();
};
THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) {
		if ( this.matrixAutoUpdate ) {
		forceUpdate |= this.updateMatrix();
	}
		if ( forceUpdate || this.matrixWorldNeedsUpdate ) {
		if( parentSkinMatrix ) {
			this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix );
		} else {
			this.skinMatrix.copy( this.matrix );
		}
		this.matrixWorldNeedsUpdate = false;
		forceUpdate = true;
	}
		var child, i, l = this.children.length;
	for ( i = 0; i < l; i ++ ) {
		this.children[ i ].update( this.skinMatrix, forceUpdate );
	}
};
THREE.Scene = function () {
	THREE.Object3D.call( this );
	this.fog = null;
	this.overrideMaterial = null;
	this.autoUpdate = true; 	this.matrixAutoUpdate = false;
	this.__objects = [];
	this.__lights = [];
	this.__objectsAdded = [];
	this.__objectsRemoved = [];
};
THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );
THREE.Scene.prototype.__addObject = function ( object ) {
	if ( object instanceof THREE.Light ) {
		if ( this.__lights.indexOf( object ) === - 1 ) {
			this.__lights.push( object );
		}
		if ( object.target && object.target.parent === undefined ) {
			this.add( object.target );
		}
	} else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) {
		if ( this.__objects.indexOf( object ) === - 1 ) {
			this.__objects.push( object );
			this.__objectsAdded.push( object );
						var i = this.__objectsRemoved.indexOf( object );
			if ( i !== -1 ) {
				this.__objectsRemoved.splice( i, 1 );
			}
		}
	}
	for ( var c = 0; c < object.children.length; c ++ ) {
		this.__addObject( object.children[ c ] );
	}
};
THREE.Scene.prototype.__removeObject = function ( object ) {
	if ( object instanceof THREE.Light ) {
		var i = this.__lights.indexOf( object );
		if ( i !== -1 ) {
			this.__lights.splice( i, 1 );
		}
	} else if ( !( object instanceof THREE.Camera ) ) {
		var i = this.__objects.indexOf( object );
		if( i !== -1 ) {
			this.__objects.splice( i, 1 );
			this.__objectsRemoved.push( object );
						var ai = this.__objectsAdded.indexOf( object );
			if ( ai !== -1 ) {
				this.__objectsAdded.splice( ai, 1 );
			}
		}
	}
	for ( var c = 0; c < object.children.length; c ++ ) {
		this.__removeObject( object.children[ c ] );
	}
};
THREE.Scene.prototype.clone = function ( object ) {
	if ( object === undefined ) object = new THREE.Scene();
	THREE.Object3D.prototype.clone.call(this, object);
	if ( this.fog !== null ) object.fog = this.fog.clone();
	if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone();
	object.autoUpdate = this.autoUpdate;
	object.matrixAutoUpdate = this.matrixAutoUpdate;
	return object;
};
THREE.Fog = function ( hex, near, far ) {
	this.name = '';
	this.color = new THREE.Color( hex );
	this.near = ( near !== undefined ) ? near : 1;
	this.far = ( far !== undefined ) ? far : 1000;
};
THREE.Fog.prototype.clone = function () {
	return new THREE.Fog( this.color.getHex(), this.near, this.far );
};
THREE.FogExp2 = function ( hex, density ) {
	this.name = '';
	this.color = new THREE.Color( hex );
	this.density = ( density !== undefined ) ? density : 0.00025;
};
THREE.FogExp2.prototype.clone = function () {
	return new THREE.FogExp2( this.color.getHex(), this.density );
};
THREE.ShaderChunk = {
		fog_pars_fragment: [
		"#ifdef USE_FOG",
			"uniform vec3 fogColor;",
			"#ifdef FOG_EXP2",
				"uniform float fogDensity;",
			"#else",
				"uniform float fogNear;",
				"uniform float fogFar;",
			"#endif",
		"#endif"
	].join("\n"),
	fog_fragment: [
		"#ifdef USE_FOG",
			"float depth = gl_FragCoord.z / gl_FragCoord.w;",
			"#ifdef FOG_EXP2",
				"const float LOG2 = 1.442695;",
				"float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
				"fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
			"#else",
				"float fogFactor = smoothstep( fogNear, fogFar, depth );",
			"#endif",
			"gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",
		"#endif"
	].join("\n"),
		envmap_pars_fragment: [
		"#ifdef USE_ENVMAP",
			"uniform float reflectivity;",
			"uniform samplerCube envMap;",
			"uniform float flipEnvMap;",
			"uniform int combine;",
			"#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",
				"uniform bool useRefract;",
				"uniform float refractionRatio;",
			"#else",
				"varying vec3 vReflect;",
			"#endif",
		"#endif"
	].join("\n"),
	envmap_fragment: [
		"#ifdef USE_ENVMAP",
			"vec3 reflectVec;",
			"#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",
				"vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
				"if ( useRefract ) {",
					"reflectVec = refract( cameraToVertex, normal, refractionRatio );",
				"} else { ",
					"reflectVec = reflect( cameraToVertex, normal );",
				"}",
			"#else",
				"reflectVec = vReflect;",
			"#endif",
			"#ifdef DOUBLE_SIDED",
				"float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
				"vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",
			"#else",
				"vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",
			"#endif",
			"#ifdef GAMMA_INPUT",
				"cubeColor.xyz *= cubeColor.xyz;",
			"#endif",
			"if ( combine == 1 ) {",
				"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );",
			"} else if ( combine == 2 ) {",
				"gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;",
			"} else {",
				"gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );",
			"}",
		"#endif"
	].join("\n"),
	envmap_pars_vertex: [
		"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",
			"varying vec3 vReflect;",
			"uniform float refractionRatio;",
			"uniform bool useRefract;",
		"#endif"
	].join("\n"),
	worldpos_vertex : [
		"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )",
			"#ifdef USE_SKINNING",
				"vec4 worldPosition = modelMatrix * skinned;",
			"#endif",
			"#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",
				"vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );",
			"#endif",
			"#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",
				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
			"#endif",
		"#endif"
	].join("\n"),
	envmap_vertex : [
		"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",
			"vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;",
			"worldNormal = normalize( worldNormal );",
			"vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );",
			"if ( useRefract ) {",
				"vReflect = refract( cameraToVertex, worldNormal, refractionRatio );",
			"} else {",
				"vReflect = reflect( cameraToVertex, worldNormal );",
			"}",
		"#endif"
	].join("\n"),
		map_particle_pars_fragment: [
		"#ifdef USE_MAP",
			"uniform sampler2D map;",
		"#endif"
	].join("\n"),
	map_particle_fragment: [
		"#ifdef USE_MAP",
			"gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );",
		"#endif"
	].join("\n"),
		map_pars_vertex: [
		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",
			"varying vec2 vUv;",
			"uniform vec4 offsetRepeat;",
		"#endif"
	].join("\n"),
	map_pars_fragment: [
		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",
			"varying vec2 vUv;",
		"#endif",
		"#ifdef USE_MAP",
			"uniform sampler2D map;",
		"#endif"
	].join("\n"),
	map_vertex: [
		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",
			"vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",
		"#endif"
	].join("\n"),
	map_fragment: [
		"#ifdef USE_MAP",
			"vec4 texelColor = texture2D( map, vUv );",
			"#ifdef GAMMA_INPUT",
				"texelColor.xyz *= texelColor.xyz;",
			"#endif",
			"gl_FragColor = gl_FragColor * texelColor;",
		"#endif"
	].join("\n"),
		lightmap_pars_fragment: [
		"#ifdef USE_LIGHTMAP",
			"varying vec2 vUv2;",
			"uniform sampler2D lightMap;",
		"#endif"
	].join("\n"),
	lightmap_pars_vertex: [
		"#ifdef USE_LIGHTMAP",
			"varying vec2 vUv2;",
		"#endif"
	].join("\n"),
	lightmap_fragment: [
		"#ifdef USE_LIGHTMAP",
			"gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );",
		"#endif"
	].join("\n"),
	lightmap_vertex: [
		"#ifdef USE_LIGHTMAP",
			"vUv2 = uv2;",
		"#endif"
	].join("\n"),
		bumpmap_pars_fragment: [
		"#ifdef USE_BUMPMAP",
			"uniform sampler2D bumpMap;",
			"uniform float bumpScale;",
												"vec2 dHdxy_fwd() {",
				"vec2 dSTdx = dFdx( vUv );",
				"vec2 dSTdy = dFdy( vUv );",
				"float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
				"float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
				"float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",
				"return vec2( dBx, dBy );",
			"}",
			"vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",
				"vec3 vSigmaX = dFdx( surf_pos );",
				"vec3 vSigmaY = dFdy( surf_pos );",
				"vec3 vN = surf_norm;",						"vec3 R1 = cross( vSigmaY, vN );",
				"vec3 R2 = cross( vN, vSigmaX );",
				"float fDet = dot( vSigmaX, R1 );",
				"vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
				"return normalize( abs( fDet ) * surf_norm - vGrad );",
			"}",
		"#endif"
	].join("\n"),
		normalmap_pars_fragment: [
		"#ifdef USE_NORMALMAP",
			"uniform sampler2D normalMap;",
			"uniform vec2 normalScale;",
									"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {",
				"vec3 q0 = dFdx( eye_pos.xyz );",
				"vec3 q1 = dFdy( eye_pos.xyz );",
				"vec2 st0 = dFdx( vUv.st );",
				"vec2 st1 = dFdy( vUv.st );",
				"vec3 S = normalize(  q0 * st1.t - q1 * st0.t );",
				"vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
				"vec3 N = normalize( surf_norm );",
				"vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;",
				"mapN.xy = normalScale * mapN.xy;",
				"mat3 tsn = mat3( S, T, N );",
				"return normalize( tsn * mapN );",
			"}",
		"#endif"
	].join("\n"),
		specularmap_pars_fragment: [
		"#ifdef USE_SPECULARMAP",
			"uniform sampler2D specularMap;",
		"#endif"
	].join("\n"),
	specularmap_fragment: [
		"float specularStrength;",
		"#ifdef USE_SPECULARMAP",
			"vec4 texelSpecular = texture2D( specularMap, vUv );",
			"specularStrength = texelSpecular.r;",
		"#else",
			"specularStrength = 1.0;",
		"#endif"
	].join("\n"),
		lights_lambert_pars_vertex: [
		"uniform vec3 ambient;",
		"uniform vec3 diffuse;",
		"uniform vec3 emissive;",
		"uniform vec3 ambientLightColor;",
		"#if MAX_DIR_LIGHTS > 0",
			"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
			"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
		"#endif",
		"#if MAX_HEMI_LIGHTS > 0",
			"uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
			"uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
			"uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
		"#endif",
		"#if MAX_POINT_LIGHTS > 0",
			"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
			"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
			"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
			"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
			"uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
			"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
			"uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
			"uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
		"#endif",
		"#ifdef WRAP_AROUND",
			"uniform vec3 wrapRGB;",
		"#endif"
	].join("\n"),
	lights_lambert_vertex: [
		"vLightFront = vec3( 0.0 );",
		"#ifdef DOUBLE_SIDED",
			"vLightBack = vec3( 0.0 );",
		"#endif",
		"transformedNormal = normalize( transformedNormal );",
		"#if MAX_DIR_LIGHTS > 0",
		"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
			"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
			"vec3 dirVector = normalize( lDirection.xyz );",
			"float dotProduct = dot( transformedNormal, dirVector );",
			"vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );",
			"#ifdef DOUBLE_SIDED",
				"vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
				"#ifdef WRAP_AROUND",
					"vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
				"#endif",
			"#endif",
			"#ifdef WRAP_AROUND",
				"vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
				"directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );",
				"#ifdef DOUBLE_SIDED",
					"directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );",
				"#endif",
			"#endif",
			"vLightFront += directionalLightColor[ i ] * directionalLightWeighting;",
			"#ifdef DOUBLE_SIDED",
				"vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;",
			"#endif",
		"}",
		"#endif",
		"#if MAX_POINT_LIGHTS > 0",
			"for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
				"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
				"float lDistance = 1.0;",
				"if ( pointLightDistance[ i ] > 0.0 )",
					"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
				"lVector = normalize( lVector );",
				"float dotProduct = dot( transformedNormal, lVector );",
				"vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );",
				"#ifdef DOUBLE_SIDED",
					"vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
					"#ifdef WRAP_AROUND",
						"vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
					"#endif",
				"#endif",
				"#ifdef WRAP_AROUND",
					"vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
					"pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );",
					"#ifdef DOUBLE_SIDED",
						"pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );",
					"#endif",
				"#endif",
				"vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;",
				"#ifdef DOUBLE_SIDED",
					"vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;",
				"#endif",
			"}",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
				"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
				"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );",
				"if ( spotEffect > spotLightAngleCos[ i ] ) {",
					"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
					"float lDistance = 1.0;",
					"if ( spotLightDistance[ i ] > 0.0 )",
						"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
					"lVector = normalize( lVector );",
					"float dotProduct = dot( transformedNormal, lVector );",
					"vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );",
					"#ifdef DOUBLE_SIDED",
						"vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
						"#ifdef WRAP_AROUND",
							"vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
						"#endif",
					"#endif",
					"#ifdef WRAP_AROUND",
						"vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
						"spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );",
						"#ifdef DOUBLE_SIDED",
							"spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );",
						"#endif",
					"#endif",
					"vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;",
					"#ifdef DOUBLE_SIDED",
						"vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;",
					"#endif",
				"}",
			"}",
		"#endif",
		"#if MAX_HEMI_LIGHTS > 0",
			"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
				"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
				"vec3 lVector = normalize( lDirection.xyz );",
				"float dotProduct = dot( transformedNormal, lVector );",
				"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
				"float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;",
				"vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
				"#ifdef DOUBLE_SIDED",
					"vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );",
				"#endif",
			"}",
		"#endif",
		"vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;",
		"#ifdef DOUBLE_SIDED",
			"vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;",
		"#endif"
	].join("\n"),
		lights_phong_pars_vertex: [
		"#ifndef PHONG_PER_PIXEL",
		"#if MAX_POINT_LIGHTS > 0",
			"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
			"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
			"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
			"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
			"varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];",
		"#endif",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",
			"varying vec3 vWorldPosition;",
		"#endif"
	].join("\n"),
	lights_phong_vertex: [
		"#ifndef PHONG_PER_PIXEL",
		"#if MAX_POINT_LIGHTS > 0",
			"for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
				"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
				"float lDistance = 1.0;",
				"if ( pointLightDistance[ i ] > 0.0 )",
					"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
				"vPointLight[ i ] = vec4( lVector, lDistance );",
			"}",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
				"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
				"float lDistance = 1.0;",
				"if ( spotLightDistance[ i ] > 0.0 )",
					"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
				"vSpotLight[ i ] = vec4( lVector, lDistance );",
			"}",
		"#endif",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",
			"vWorldPosition = worldPosition.xyz;",
		"#endif"
	].join("\n"),
	lights_phong_pars_fragment: [
		"uniform vec3 ambientLightColor;",
		"#if MAX_DIR_LIGHTS > 0",
			"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
			"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
		"#endif",
		"#if MAX_HEMI_LIGHTS > 0",
			"uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
			"uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
			"uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
		"#endif",
		"#if MAX_POINT_LIGHTS > 0",
			"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
			"#ifdef PHONG_PER_PIXEL",
				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
			"#else",
				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
			"#endif",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
			"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
			"uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
			"uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
			"uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
			"#ifdef PHONG_PER_PIXEL",
				"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
			"#else",
				"varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];",
			"#endif",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",
			"varying vec3 vWorldPosition;",
		"#endif",
		"#ifdef WRAP_AROUND",
			"uniform vec3 wrapRGB;",
		"#endif",
		"varying vec3 vViewPosition;",
		"varying vec3 vNormal;"
	].join("\n"),
	lights_phong_fragment: [
		"vec3 normal = normalize( vNormal );",
		"vec3 viewPosition = normalize( vViewPosition );",
		"#ifdef DOUBLE_SIDED",
			"normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
		"#endif",
		"#ifdef USE_NORMALMAP",
			"normal = perturbNormal2Arb( -vViewPosition, normal );",
		"#elif defined( USE_BUMPMAP )",
			"normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",
		"#endif",
		"#if MAX_POINT_LIGHTS > 0",
			"vec3 pointDiffuse  = vec3( 0.0 );",
			"vec3 pointSpecular = vec3( 0.0 );",
			"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
				"#ifdef PHONG_PER_PIXEL",
					"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
					"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
					"float lDistance = 1.0;",
					"if ( pointLightDistance[ i ] > 0.0 )",
						"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
					"lVector = normalize( lVector );",
				"#else",
					"vec3 lVector = normalize( vPointLight[ i ].xyz );",
					"float lDistance = vPointLight[ i ].w;",
				"#endif",
								"float dotProduct = dot( normal, lVector );",
				"#ifdef WRAP_AROUND",
					"float pointDiffuseWeightFull = max( dotProduct, 0.0 );",
					"float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
					"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
				"#else",
					"float pointDiffuseWeight = max( dotProduct, 0.0 );",
				"#endif",
				"pointDiffuse  += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;",
								"vec3 pointHalfVector = normalize( lVector + viewPosition );",
				"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
				"float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
				"#ifdef PHYSICALLY_BASED_SHADING",
										"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
					"vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );",
					"pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;",
				"#else",
					"pointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;",
				"#endif",
			"}",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"vec3 spotDiffuse  = vec3( 0.0 );",
			"vec3 spotSpecular = vec3( 0.0 );",
			"for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
				"#ifdef PHONG_PER_PIXEL",
					"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
					"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
					"float lDistance = 1.0;",
					"if ( spotLightDistance[ i ] > 0.0 )",
						"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
					"lVector = normalize( lVector );",
				"#else",
					"vec3 lVector = normalize( vSpotLight[ i ].xyz );",
					"float lDistance = vSpotLight[ i ].w;",
				"#endif",
				"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",
				"if ( spotEffect > spotLightAngleCos[ i ] ) {",
					"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
										"float dotProduct = dot( normal, lVector );",
					"#ifdef WRAP_AROUND",
						"float spotDiffuseWeightFull = max( dotProduct, 0.0 );",
						"float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
						"vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",
					"#else",
						"float spotDiffuseWeight = max( dotProduct, 0.0 );",
					"#endif",
					"spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;",
										"vec3 spotHalfVector = normalize( lVector + viewPosition );",
					"float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
					"float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );",
					"#ifdef PHYSICALLY_BASED_SHADING",
												"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
						"vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );",
						"spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;",
					"#else",
						"spotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;",
					"#endif",
				"}",
			"}",
		"#endif",
		"#if MAX_DIR_LIGHTS > 0",
			"vec3 dirDiffuse  = vec3( 0.0 );",
			"vec3 dirSpecular = vec3( 0.0 );" ,
			"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
				"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
				"vec3 dirVector = normalize( lDirection.xyz );",
								"float dotProduct = dot( normal, dirVector );",
				"#ifdef WRAP_AROUND",
					"float dirDiffuseWeightFull = max( dotProduct, 0.0 );",
					"float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
					"vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );",
				"#else",
					"float dirDiffuseWeight = max( dotProduct, 0.0 );",
				"#endif",
				"dirDiffuse  += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;",
								"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
				"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
				"float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );",
				"#ifdef PHYSICALLY_BASED_SHADING",
					/*
										"const float F0 = 0.128;",
					"float base = 1.0 - dot( viewPosition, dirHalfVector );",
					"float exponential = pow( base, 5.0 );",
					"float fresnel = exponential + F0 * ( 1.0 - exponential );",
					*/
					/*
										"const float mFresnelBias = 0.08;",
					"const float mFresnelScale = 0.3;",
					"const float mFresnelPower = 5.0;",
					"float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );",
					*/
										"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
										"vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
					"dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
				"#else",
					"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;",
				"#endif",
			"}",
		"#endif",
		"#if MAX_HEMI_LIGHTS > 0",
			"vec3 hemiDiffuse  = vec3( 0.0 );",
			"vec3 hemiSpecular = vec3( 0.0 );" ,
			"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
				"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
				"vec3 lVector = normalize( lDirection.xyz );",
								"float dotProduct = dot( normal, lVector );",
				"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
				"vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
				"hemiDiffuse += diffuse * hemiColor;",
								"vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
				"float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
				"float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );",
								"vec3 lVectorGround = -lVector;",
				"vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
				"float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
				"float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );",
				"#ifdef PHYSICALLY_BASED_SHADING",
					"float dotProductGround = dot( normal, lVectorGround );",
										"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
					"vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );",
					"vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );",
					"hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
				"#else",
					"hemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;",
				"#endif",
			"}",
		"#endif",
		"vec3 totalDiffuse = vec3( 0.0 );",
		"vec3 totalSpecular = vec3( 0.0 );",
		"#if MAX_DIR_LIGHTS > 0",
			"totalDiffuse += dirDiffuse;",
			"totalSpecular += dirSpecular;",
		"#endif",
		"#if MAX_HEMI_LIGHTS > 0",
			"totalDiffuse += hemiDiffuse;",
			"totalSpecular += hemiSpecular;",
		"#endif",
		"#if MAX_POINT_LIGHTS > 0",
			"totalDiffuse += pointDiffuse;",
			"totalSpecular += pointSpecular;",
		"#endif",
		"#if MAX_SPOT_LIGHTS > 0",
			"totalDiffuse += spotDiffuse;",
			"totalSpecular += spotSpecular;",
		"#endif",
		"#ifdef METAL",
			"gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );",
		"#else",
			"gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;",
		"#endif"
	].join("\n"),
		color_pars_fragment: [
		"#ifdef USE_COLOR",
			"varying vec3 vColor;",
		"#endif"
	].join("\n"),
	color_fragment: [
		"#ifdef USE_COLOR",
			"gl_FragColor = gl_FragColor * vec4( vColor, opacity );",
		"#endif"
	].join("\n"),
	color_pars_vertex: [
		"#ifdef USE_COLOR",
			"varying vec3 vColor;",
		"#endif"
	].join("\n"),
	color_vertex: [
		"#ifdef USE_COLOR",
			"#ifdef GAMMA_INPUT",
				"vColor = color * color;",
			"#else",
				"vColor = color;",
			"#endif",
		"#endif"
	].join("\n"),
		skinning_pars_vertex: [
		"#ifdef USE_SKINNING",
			"#ifdef BONE_TEXTURE",
				"uniform sampler2D boneTexture;",
				"mat4 getBoneMatrix( const in float i ) {",
					"float j = i * 4.0;",
					"float x = mod( j, N_BONE_PIXEL_X );",
					"float y = floor( j / N_BONE_PIXEL_X );",
					"const float dx = 1.0 / N_BONE_PIXEL_X;",
					"const float dy = 1.0 / N_BONE_PIXEL_Y;",
					"y = dy * ( y + 0.5 );",
					"vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
					"vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
					"vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
					"vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",
					"mat4 bone = mat4( v1, v2, v3, v4 );",
					"return bone;",
				"}",
			"#else",
				"uniform mat4 boneGlobalMatrices[ MAX_BONES ];",
				"mat4 getBoneMatrix( const in float i ) {",
					"mat4 bone = boneGlobalMatrices[ int(i) ];",
					"return bone;",
				"}",
			"#endif",
		"#endif"
	].join("\n"),
	skinbase_vertex: [
		"#ifdef USE_SKINNING",
			"mat4 boneMatX = getBoneMatrix( skinIndex.x );",
			"mat4 boneMatY = getBoneMatrix( skinIndex.y );",
		"#endif"
	].join("\n"),
	skinning_vertex: [
		"#ifdef USE_SKINNING",
			"#ifdef USE_MORPHTARGETS",
			"vec4 skinVertex = vec4( morphed, 1.0 );",
			"#else",
			"vec4 skinVertex = vec4( position, 1.0 );",
			"#endif",
			"vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
			"skinned 	  += boneMatY * skinVertex * skinWeight.y;",
		"#endif"
	].join("\n"),
		morphtarget_pars_vertex: [
		"#ifdef USE_MORPHTARGETS",
			"#ifndef USE_MORPHNORMALS",
			"uniform float morphTargetInfluences[ 8 ];",
			"#else",
			"uniform float morphTargetInfluences[ 4 ];",
			"#endif",
		"#endif"
	].join("\n"),
	morphtarget_vertex: [
		"#ifdef USE_MORPHTARGETS",
			"vec3 morphed = vec3( 0.0 );",
			"morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];",
			"morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];",
			"morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];",
			"morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];",
			"#ifndef USE_MORPHNORMALS",
			"morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];",
			"morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];",
			"morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];",
			"morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];",
			"#endif",
			"morphed += position;",
		"#endif"
	].join("\n"),
	default_vertex : [
		"vec4 mvPosition;",
		"#ifdef USE_SKINNING",
			"mvPosition = modelViewMatrix * skinned;",
		"#endif",
		"#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )",
			"mvPosition = modelViewMatrix * vec4( morphed, 1.0 );",
		"#endif",
		"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )",
			"mvPosition = modelViewMatrix * vec4( position, 1.0 );",
		"#endif",
		"gl_Position = projectionMatrix * mvPosition;"
	].join("\n"),
	morphnormal_vertex: [
		"#ifdef USE_MORPHNORMALS",
			"vec3 morphedNormal = vec3( 0.0 );",
			"morphedNormal +=  ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];",
			"morphedNormal +=  ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];",
			"morphedNormal +=  ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];",
			"morphedNormal +=  ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];",
			"morphedNormal += normal;",
		"#endif"
	].join("\n"),
	skinnormal_vertex: [
		"#ifdef USE_SKINNING",
			"mat4 skinMatrix = skinWeight.x * boneMatX;",
			"skinMatrix 	+= skinWeight.y * boneMatY;",
			"#ifdef USE_MORPHNORMALS",
			"vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );",
			"#else",
			"vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );",
			"#endif",
		"#endif"
	].join("\n"),
	defaultnormal_vertex: [
		"vec3 objectNormal;",
		"#ifdef USE_SKINNING",
			"objectNormal = skinnedNormal.xyz;",
		"#endif",
		"#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )",
			"objectNormal = morphedNormal;",
		"#endif",
		"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )",
			"objectNormal = normal;",
		"#endif",
		"#ifdef FLIP_SIDED",
			"objectNormal = -objectNormal;",
		"#endif",
		"vec3 transformedNormal = normalMatrix * objectNormal;"
	].join("\n"),
					shadowmap_pars_fragment: [
		"#ifdef USE_SHADOWMAP",
			"uniform sampler2D shadowMap[ MAX_SHADOWS ];",
			"uniform vec2 shadowMapSize[ MAX_SHADOWS ];",
			"uniform float shadowDarkness[ MAX_SHADOWS ];",
			"uniform float shadowBias[ MAX_SHADOWS ];",
			"varying vec4 vShadowCoord[ MAX_SHADOWS ];",
			"float unpackDepth( const in vec4 rgba_depth ) {",
				"const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
				"float depth = dot( rgba_depth, bit_shift );",
				"return depth;",
			"}",
		"#endif"
	].join("\n"),
	shadowmap_fragment: [
		"#ifdef USE_SHADOWMAP",
			"#ifdef SHADOWMAP_DEBUG",
				"vec3 frustumColors[3];",
				"frustumColors[0] = vec3( 1.0, 0.5, 0.0 );",
				"frustumColors[1] = vec3( 0.0, 1.0, 0.8 );",
				"frustumColors[2] = vec3( 0.0, 0.5, 1.0 );",
			"#endif",
			"#ifdef SHADOWMAP_CASCADE",
				"int inFrustumCount = 0;",
			"#endif",
			"float fDepth;",
			"vec3 shadowColor = vec3( 1.0 );",
			"for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
				"vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;",
												"bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );",
				"bool inFrustum = all( inFrustumVec );",
																"#ifdef SHADOWMAP_CASCADE",
					"inFrustumCount += int( inFrustum );",
					"bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );",
				"#else",
					"bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );",
				"#endif",
				"bool frustumTest = all( frustumTestVec );",
				"if ( frustumTest ) {",
					"shadowCoord.z += shadowBias[ i ];",
					"#if defined( SHADOWMAP_TYPE_PCF )",
																								"float shadow = 0.0;",
						/*
																		"for ( float y = -1.25; y <= 1.25; y += 1.25 )",
							"for ( float x = -1.25; x <= 1.25; x += 1.25 ) {",
								"vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );",
																								"float fDepth = unpackDepth( rgbaDepth );",
								"if ( fDepth < shadowCoord.z )",
									"shadow += 1.0;",
						"}",
						"shadow /= 9.0;",
						*/
						"const float shadowDelta = 1.0 / 9.0;",
						"float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
						"float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",
						"float dx0 = -1.25 * xPixelOffset;",
						"float dy0 = -1.25 * yPixelOffset;",
						"float dx1 = 1.25 * xPixelOffset;",
						"float dy1 = 1.25 * yPixelOffset;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
						"shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",
					"#elif defined( SHADOWMAP_TYPE_PCF_SOFT )",
																								"float shadow = 0.0;",
						"float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
						"float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",
						"float dx0 = -1.0 * xPixelOffset;",
						"float dy0 = -1.0 * yPixelOffset;",
						"float dx1 = 1.0 * xPixelOffset;",
						"float dy1 = 1.0 * yPixelOffset;",
						"mat3 shadowKernel;",
						"mat3 depthKernel;",
						"depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
						"depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
						"depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
						"depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
						"depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
						"depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
						"depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
						"depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
						"depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
						"vec3 shadowZ = vec3( shadowCoord.z );",
						"shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));",
						"shadowKernel[0] *= vec3(0.25);",
													
						"shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));",
						"shadowKernel[1] *= vec3(0.25);",
						"shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));",
						"shadowKernel[2] *= vec3(0.25);",
						"vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );",
						"shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );",
						"shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );",
						"vec4 shadowValues;",
						"shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );",
						"shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );",
						"shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );",
						"shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );",
						"shadow = dot( shadowValues, vec4( 1.0 ) );",
						"shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",
					"#else",
						"vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );",
						"float fDepth = unpackDepth( rgbaDepth );",
						"if ( fDepth < shadowCoord.z )",
														"shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );",
																			"#endif",
				"}",
				"#ifdef SHADOWMAP_DEBUG",
					"#ifdef SHADOWMAP_CASCADE",
						"if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];",
					"#else",
						"if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];",
					"#endif",
				"#endif",
			"}",
			"#ifdef GAMMA_OUTPUT",
				"shadowColor *= shadowColor;",
			"#endif",
			"gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;",
		"#endif"
	].join("\n"),
	shadowmap_pars_vertex: [
		"#ifdef USE_SHADOWMAP",
			"varying vec4 vShadowCoord[ MAX_SHADOWS ];",
			"uniform mat4 shadowMatrix[ MAX_SHADOWS ];",
		"#endif"
	].join("\n"),
	shadowmap_vertex: [
		"#ifdef USE_SHADOWMAP",
			"for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
				"vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;",
			"}",
		"#endif"
	].join("\n"),
		alphatest_fragment: [
		"#ifdef ALPHATEST",
			"if ( gl_FragColor.a < ALPHATEST ) discard;",
		"#endif"
	].join("\n"),
		linear_to_gamma_fragment: [
		"#ifdef GAMMA_OUTPUT",
			"gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",
		"#endif"
	].join("\n")
};
THREE.UniformsUtils = {
	merge: function ( uniforms ) {
		var u, p, tmp, merged = {};
		for ( u = 0; u < uniforms.length; u ++ ) {
			tmp = this.clone( uniforms[ u ] );
			for ( p in tmp ) {
				merged[ p ] = tmp[ p ];
			}
		}
		return merged;
	},
	clone: function ( uniforms_src ) {
		var u, p, parameter, parameter_src, uniforms_dst = {};
		for ( u in uniforms_src ) {
			uniforms_dst[ u ] = {};
			for ( p in uniforms_src[ u ] ) {
				parameter_src = uniforms_src[ u ][ p ];
				if ( parameter_src instanceof THREE.Color ||
					 parameter_src instanceof THREE.Vector2 ||
					 parameter_src instanceof THREE.Vector3 ||
					 parameter_src instanceof THREE.Vector4 ||
					 parameter_src instanceof THREE.Matrix4 ||
					 parameter_src instanceof THREE.Texture ) {
					uniforms_dst[ u ][ p ] = parameter_src.clone();
				} else if ( parameter_src instanceof Array ) {
					uniforms_dst[ u ][ p ] = parameter_src.slice();
				} else {
					uniforms_dst[ u ][ p ] = parameter_src;
				}
			}
		}
		return uniforms_dst;
	}
};
THREE.UniformsLib = {
	common: {
		"diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
		"opacity" : { type: "f", value: 1.0 },
		"map" : { type: "t", value: null },
		"offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },
		"lightMap" : { type: "t", value: null },
		"specularMap" : { type: "t", value: null },
		"envMap" : { type: "t", value: null },
		"flipEnvMap" : { type: "f", value: -1 },
		"useRefract" : { type: "i", value: 0 },
		"reflectivity" : { type: "f", value: 1.0 },
		"refractionRatio" : { type: "f", value: 0.98 },
		"combine" : { type: "i", value: 0 },
		"morphTargetInfluences" : { type: "f", value: 0 }
	},
	bump: {
		"bumpMap" : { type: "t", value: null },
		"bumpScale" : { type: "f", value: 1 }
	},
	normalmap: {
		"normalMap" : { type: "t", value: null },
		"normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }
	},
	fog : {
		"fogDensity" : { type: "f", value: 0.00025 },
		"fogNear" : { type: "f", value: 1 },
		"fogFar" : { type: "f", value: 2000 },
		"fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }
	},
	lights: {
		"ambientLightColor" : { type: "fv", value: [] },
		"directionalLightDirection" : { type: "fv", value: [] },
		"directionalLightColor" : { type: "fv", value: [] },
		"hemisphereLightDirection" : { type: "fv", value: [] },
		"hemisphereLightSkyColor" : { type: "fv", value: [] },
		"hemisphereLightGroundColor" : { type: "fv", value: [] },
		"pointLightColor" : { type: "fv", value: [] },
		"pointLightPosition" : { type: "fv", value: [] },
		"pointLightDistance" : { type: "fv1", value: [] },
		"spotLightColor" : { type: "fv", value: [] },
		"spotLightPosition" : { type: "fv", value: [] },
		"spotLightDirection" : { type: "fv", value: [] },
		"spotLightDistance" : { type: "fv1", value: [] },
		"spotLightAngleCos" : { type: "fv1", value: [] },
		"spotLightExponent" : { type: "fv1", value: [] }
	},
	particle: {
		"psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
		"opacity" : { type: "f", value: 1.0 },
		"size" : { type: "f", value: 1.0 },
		"scale" : { type: "f", value: 1.0 },
		"map" : { type: "t", value: null },
		"fogDensity" : { type: "f", value: 0.00025 },
		"fogNear" : { type: "f", value: 1 },
		"fogFar" : { type: "f", value: 2000 },
		"fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }
	},
	shadowmap: {
		"shadowMap": { type: "tv", value: [] },
		"shadowMapSize": { type: "v2v", value: [] },
		"shadowBias" : { type: "fv1", value: [] },
		"shadowDarkness": { type: "fv1", value: [] },
		"shadowMatrix" : { type: "m4v", value: [] }
	}
};
THREE.ShaderLib = {
	'basic': {
		uniforms: THREE.UniformsUtils.merge( [
			THREE.UniformsLib[ "common" ],
			THREE.UniformsLib[ "fog" ],
			THREE.UniformsLib[ "shadowmap" ]
		] ),
		vertexShader: [
			THREE.ShaderChunk[ "map_pars_vertex" ],
			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
			THREE.ShaderChunk[ "envmap_pars_vertex" ],
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "skinning_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "map_vertex" ],
				THREE.ShaderChunk[ "lightmap_vertex" ],
				THREE.ShaderChunk[ "color_vertex" ],
				THREE.ShaderChunk[ "skinbase_vertex" ],
				"#ifdef USE_ENVMAP",
				THREE.ShaderChunk[ "morphnormal_vertex" ],
				THREE.ShaderChunk[ "skinnormal_vertex" ],
				THREE.ShaderChunk[ "defaultnormal_vertex" ],
				"#endif",
				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform vec3 diffuse;",
			"uniform float opacity;",
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
			THREE.ShaderChunk[ "envmap_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
			"void main() {",
				"gl_FragColor = vec4( diffuse, opacity );",
				THREE.ShaderChunk[ "map_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],
				THREE.ShaderChunk[ "specularmap_fragment" ],
				THREE.ShaderChunk[ "lightmap_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],
				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],
			"}"
		].join("\n")
	},
	'lambert': {
		uniforms: THREE.UniformsUtils.merge( [
			THREE.UniformsLib[ "common" ],
			THREE.UniformsLib[ "fog" ],
			THREE.UniformsLib[ "lights" ],
			THREE.UniformsLib[ "shadowmap" ],
			{
				"ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
				"emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
				"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
			}
		] ),
		vertexShader: [
			"#define LAMBERT",
			"varying vec3 vLightFront;",
			"#ifdef DOUBLE_SIDED",
				"varying vec3 vLightBack;",
			"#endif",
			THREE.ShaderChunk[ "map_pars_vertex" ],
			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
			THREE.ShaderChunk[ "envmap_pars_vertex" ],
			THREE.ShaderChunk[ "lights_lambert_pars_vertex" ],
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "skinning_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "map_vertex" ],
				THREE.ShaderChunk[ "lightmap_vertex" ],
				THREE.ShaderChunk[ "color_vertex" ],
				THREE.ShaderChunk[ "morphnormal_vertex" ],
				THREE.ShaderChunk[ "skinbase_vertex" ],
				THREE.ShaderChunk[ "skinnormal_vertex" ],
				THREE.ShaderChunk[ "defaultnormal_vertex" ],
				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "lights_lambert_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform float opacity;",
			"varying vec3 vLightFront;",
			"#ifdef DOUBLE_SIDED",
				"varying vec3 vLightBack;",
			"#endif",
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
			THREE.ShaderChunk[ "envmap_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
			"void main() {",
				"gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",
				THREE.ShaderChunk[ "map_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],
				THREE.ShaderChunk[ "specularmap_fragment" ],
				"#ifdef DOUBLE_SIDED",
															"if ( gl_FrontFacing )",
						"gl_FragColor.xyz *= vLightFront;",
					"else",
						"gl_FragColor.xyz *= vLightBack;",
				"#else",
					"gl_FragColor.xyz *= vLightFront;",
				"#endif",
				THREE.ShaderChunk[ "lightmap_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],
				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],
			"}"
		].join("\n")
	},
	'phong': {
		uniforms: THREE.UniformsUtils.merge( [
			THREE.UniformsLib[ "common" ],
			THREE.UniformsLib[ "bump" ],
			THREE.UniformsLib[ "normalmap" ],
			THREE.UniformsLib[ "fog" ],
			THREE.UniformsLib[ "lights" ],
			THREE.UniformsLib[ "shadowmap" ],
			{
				"ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
				"emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
				"specular" : { type: "c", value: new THREE.Color( 0x111111 ) },
				"shininess": { type: "f", value: 30 },
				"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
			}
		] ),
		vertexShader: [
			"#define PHONG",
			"varying vec3 vViewPosition;",
			"varying vec3 vNormal;",
			THREE.ShaderChunk[ "map_pars_vertex" ],
			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
			THREE.ShaderChunk[ "envmap_pars_vertex" ],
			THREE.ShaderChunk[ "lights_phong_pars_vertex" ],
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "skinning_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "map_vertex" ],
				THREE.ShaderChunk[ "lightmap_vertex" ],
				THREE.ShaderChunk[ "color_vertex" ],
				THREE.ShaderChunk[ "morphnormal_vertex" ],
				THREE.ShaderChunk[ "skinbase_vertex" ],
				THREE.ShaderChunk[ "skinnormal_vertex" ],
				THREE.ShaderChunk[ "defaultnormal_vertex" ],
				"vNormal = normalize( transformedNormal );",
				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				"vViewPosition = -mvPosition.xyz;",
				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "lights_phong_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform vec3 diffuse;",
			"uniform float opacity;",
			"uniform vec3 ambient;",
			"uniform vec3 emissive;",
			"uniform vec3 specular;",
			"uniform float shininess;",
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
			THREE.ShaderChunk[ "envmap_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
			THREE.ShaderChunk[ "normalmap_pars_fragment" ],
			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
			"void main() {",
				"gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",
				THREE.ShaderChunk[ "map_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],
				THREE.ShaderChunk[ "specularmap_fragment" ],
				THREE.ShaderChunk[ "lights_phong_fragment" ],
				THREE.ShaderChunk[ "lightmap_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],
				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],
			"}"
		].join("\n")
	},
	'particle_basic': {
		uniforms:  THREE.UniformsUtils.merge( [
			THREE.UniformsLib[ "particle" ],
			THREE.UniformsLib[ "shadowmap" ]
		] ),
		vertexShader: [
			"uniform float size;",
			"uniform float scale;",
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "color_vertex" ],
				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
				"#ifdef USE_SIZEATTENUATION",
					"gl_PointSize = size * ( scale / length( mvPosition.xyz ) );",
				"#else",
					"gl_PointSize = size;",
				"#endif",
				"gl_Position = projectionMatrix * mvPosition;",
				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform vec3 psColor;",
			"uniform float opacity;",
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_particle_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			"void main() {",
				"gl_FragColor = vec4( psColor, opacity );",
				THREE.ShaderChunk[ "map_particle_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],
			"}"
		].join("\n")
	},
	'dashed': {
		uniforms: THREE.UniformsUtils.merge( [
			THREE.UniformsLib[ "common" ],
			THREE.UniformsLib[ "fog" ],
			{
				"scale":     { type: "f", value: 1 },
				"dashSize":  { type: "f", value: 1 },
				"totalSize": { type: "f", value: 2 }
			}
		] ),
		vertexShader: [
			"uniform float scale;",
			"attribute float lineDistance;",
			"varying float vLineDistance;",
			THREE.ShaderChunk[ "color_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "color_vertex" ],
				"vLineDistance = scale * lineDistance;",
				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
				"gl_Position = projectionMatrix * mvPosition;",
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform vec3 diffuse;",
			"uniform float opacity;",
			"uniform float dashSize;",
			"uniform float totalSize;",
			"varying float vLineDistance;",
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			"void main() {",
				"if ( mod( vLineDistance, totalSize ) > dashSize ) {",
					"discard;",
				"}",
				"gl_FragColor = vec4( diffuse, opacity );",
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],
			"}"
		].join("\n")
	},
	'depth': {
		uniforms: {
			"mNear": { type: "f", value: 1.0 },
			"mFar" : { type: "f", value: 2000.0 },
			"opacity" : { type: "f", value: 1.0 }
		},
		vertexShader: [
			"void main() {",
				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform float mNear;",
			"uniform float mFar;",
			"uniform float opacity;",
			"void main() {",
				"float depth = gl_FragCoord.z / gl_FragCoord.w;",
				"float color = 1.0 - smoothstep( mNear, mFar, depth );",
				"gl_FragColor = vec4( vec3( color ), opacity );",
			"}"
		].join("\n")
	},
	'normal': {
		uniforms: {
			"opacity" : { type: "f", value: 1.0 }
		},
		vertexShader: [
			"varying vec3 vNormal;",
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			"void main() {",
				"vNormal = normalize( normalMatrix * normal );",
				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform float opacity;",
			"varying vec3 vNormal;",
			"void main() {",
				"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",
			"}"
		].join("\n")
	},
	/* -------------------------------------------------------------------------
					 ------------------------------------------------------------------------- */
	'normalmap' : {
		uniforms: THREE.UniformsUtils.merge( [
			THREE.UniformsLib[ "fog" ],
			THREE.UniformsLib[ "lights" ],
			THREE.UniformsLib[ "shadowmap" ],
			{
			"enableAO"		  : { type: "i", value: 0 },
			"enableDiffuse"	  : { type: "i", value: 0 },
			"enableSpecular"  : { type: "i", value: 0 },
			"enableReflection": { type: "i", value: 0 },
			"enableDisplacement": { type: "i", value: 0 },
			"tDisplacement": { type: "t", value: null }, 			"tDiffuse"	   : { type: "t", value: null },
			"tCube"		   : { type: "t", value: null },
			"tNormal"	   : { type: "t", value: null },
			"tSpecular"	   : { type: "t", value: null },
			"tAO"		   : { type: "t", value: null },
			"uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) },
			"uDisplacementBias": { type: "f", value: 0.0 },
			"uDisplacementScale": { type: "f", value: 1.0 },
			"uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) },
			"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
			"uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) },
			"uShininess": { type: "f", value: 30 },
			"uOpacity": { type: "f", value: 1 },
			"useRefract": { type: "i", value: 0 },
			"uRefractionRatio": { type: "f", value: 0.98 },
			"uReflectivity": { type: "f", value: 0.5 },
			"uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) },
			"uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
			"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
			}
		] ),
		fragmentShader: [
			"uniform vec3 uAmbientColor;",
			"uniform vec3 uDiffuseColor;",
			"uniform vec3 uSpecularColor;",
			"uniform float uShininess;",
			"uniform float uOpacity;",
			"uniform bool enableDiffuse;",
			"uniform bool enableSpecular;",
			"uniform bool enableAO;",
			"uniform bool enableReflection;",
			"uniform sampler2D tDiffuse;",
			"uniform sampler2D tNormal;",
			"uniform sampler2D tSpecular;",
			"uniform sampler2D tAO;",
			"uniform samplerCube tCube;",
			"uniform vec2 uNormalScale;",
			"uniform bool useRefract;",
			"uniform float uRefractionRatio;",
			"uniform float uReflectivity;",
			"varying vec3 vTangent;",
			"varying vec3 vBinormal;",
			"varying vec3 vNormal;",
			"varying vec2 vUv;",
			"uniform vec3 ambientLightColor;",
			"#if MAX_DIR_LIGHTS > 0",
				"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
				"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
			"#endif",
			"#if MAX_HEMI_LIGHTS > 0",
				"uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
				"uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
				"uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
			"#endif",
			"#if MAX_POINT_LIGHTS > 0",
				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
			"#endif",
			"#if MAX_SPOT_LIGHTS > 0",
				"uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
				"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
				"uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
				"uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
				"uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
				"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
			"#endif",
			"#ifdef WRAP_AROUND",
				"uniform vec3 wrapRGB;",
			"#endif",
			"varying vec3 vWorldPosition;",
			"varying vec3 vViewPosition;",
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			"void main() {",
				"gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",
				"vec3 specularTex = vec3( 1.0 );",
				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
				"normalTex.xy *= uNormalScale;",
				"normalTex = normalize( normalTex );",
				"if( enableDiffuse ) {",
					"#ifdef GAMMA_INPUT",
						"vec4 texelColor = texture2D( tDiffuse, vUv );",
						"texelColor.xyz *= texelColor.xyz;",
						"gl_FragColor = gl_FragColor * texelColor;",
					"#else",
						"gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",
					"#endif",
				"}",
				"if( enableAO ) {",
					"#ifdef GAMMA_INPUT",
						"vec4 aoColor = texture2D( tAO, vUv );",
						"aoColor.xyz *= aoColor.xyz;",
						"gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",
					"#else",
						"gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",
					"#endif",
				"}",
				"if( enableSpecular )",
					"specularTex = texture2D( tSpecular, vUv ).xyz;",
				"mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );",
				"vec3 finalNormal = tsb * normalTex;",
				"#ifdef FLIP_SIDED",
					"finalNormal = -finalNormal;",
				"#endif",
				"vec3 normal = normalize( finalNormal );",
				"vec3 viewPosition = normalize( vViewPosition );",
								"#if MAX_POINT_LIGHTS > 0",
					"vec3 pointDiffuse = vec3( 0.0 );",
					"vec3 pointSpecular = vec3( 0.0 );",
					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
						"vec3 pointVector = lPosition.xyz + vViewPosition.xyz;",
						"float pointDistance = 1.0;",
						"if ( pointLightDistance[ i ] > 0.0 )",
							"pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );",
						"pointVector = normalize( pointVector );",
												"#ifdef WRAP_AROUND",
							"float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );",
							"float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );",
							"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
						"#else",
							"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
						"#endif",
						"pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;",
												"vec3 pointHalfVector = normalize( pointVector + viewPosition );",
						"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
						"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );",
						"#ifdef PHYSICALLY_BASED_SHADING",
														"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
							"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );",
							"pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
						"#else",
							"pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;",
						"#endif",
					"}",
				"#endif",
								"#if MAX_SPOT_LIGHTS > 0",
					"vec3 spotDiffuse = vec3( 0.0 );",
					"vec3 spotSpecular = vec3( 0.0 );",
					"for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
						"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
						"vec3 spotVector = lPosition.xyz + vViewPosition.xyz;",
						"float spotDistance = 1.0;",
						"if ( spotLightDistance[ i ] > 0.0 )",
							"spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );",
						"spotVector = normalize( spotVector );",
						"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",
						"if ( spotEffect > spotLightAngleCos[ i ] ) {",
							"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
														"#ifdef WRAP_AROUND",
								"float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );",
								"float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );",
								"vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",
							"#else",
								"float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );",
							"#endif",
							"spotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;",
														"vec3 spotHalfVector = normalize( spotVector + viewPosition );",
							"float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
							"float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );",
							"#ifdef PHYSICALLY_BASED_SHADING",
																"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
								"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );",
								"spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;",
							"#else",
								"spotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;",
							"#endif",
						"}",
					"}",
				"#endif",
								"#if MAX_DIR_LIGHTS > 0",
					"vec3 dirDiffuse = vec3( 0.0 );",
					"vec3 dirSpecular = vec3( 0.0 );",
					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
						"vec3 dirVector = normalize( lDirection.xyz );",
												"#ifdef WRAP_AROUND",
							"float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );",
							"float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
							"vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );",
						"#else",
							"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
						"#endif",
						"dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;",
												"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
						"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
						"float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );",
						"#ifdef PHYSICALLY_BASED_SHADING",
														"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
							"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
							"dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
						"#else",
							"dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;",
						"#endif",
					"}",
				"#endif",
								"#if MAX_HEMI_LIGHTS > 0",
					"vec3 hemiDiffuse  = vec3( 0.0 );",
					"vec3 hemiSpecular = vec3( 0.0 );" ,
					"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
						"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
						"vec3 lVector = normalize( lDirection.xyz );",
												"float dotProduct = dot( normal, lVector );",
						"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
						"vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
						"hemiDiffuse += uDiffuseColor * hemiColor;",
												"vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
						"float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
						"float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );",
												"vec3 lVectorGround = -lVector;",
						"vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
						"float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
						"float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );",
						"#ifdef PHYSICALLY_BASED_SHADING",
							"float dotProductGround = dot( normal, lVectorGround );",
														"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
							"vec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );",
							"vec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );",
							"hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
						"#else",
							"hemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;",
						"#endif",
					"}",
				"#endif",
								"vec3 totalDiffuse = vec3( 0.0 );",
				"vec3 totalSpecular = vec3( 0.0 );",
				"#if MAX_DIR_LIGHTS > 0",
					"totalDiffuse += dirDiffuse;",
					"totalSpecular += dirSpecular;",
				"#endif",
				"#if MAX_HEMI_LIGHTS > 0",
					"totalDiffuse += hemiDiffuse;",
					"totalSpecular += hemiSpecular;",
				"#endif",
				"#if MAX_POINT_LIGHTS > 0",
					"totalDiffuse += pointDiffuse;",
					"totalSpecular += pointSpecular;",
				"#endif",
				"#if MAX_SPOT_LIGHTS > 0",
					"totalDiffuse += spotDiffuse;",
					"totalSpecular += spotSpecular;",
				"#endif",
				"#ifdef METAL",
					"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );",
				"#else",
					"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;",
				"#endif",
				"if ( enableReflection ) {",
					"vec3 vReflect;",
					"vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
					"if ( useRefract ) {",
						"vReflect = refract( cameraToVertex, normal, uRefractionRatio );",
					"} else {",
						"vReflect = reflect( cameraToVertex, normal );",
					"}",
					"vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",
					"#ifdef GAMMA_INPUT",
						"cubeColor.xyz *= cubeColor.xyz;",
					"#endif",
					"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );",
				"}",
				THREE.ShaderChunk[ "shadowmap_fragment" ],
				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],
			"}"
		].join("\n"),
		vertexShader: [
			"attribute vec4 tangent;",
			"uniform vec2 uOffset;",
			"uniform vec2 uRepeat;",
			"uniform bool enableDisplacement;",
			"#ifdef VERTEX_TEXTURES",
				"uniform sampler2D tDisplacement;",
				"uniform float uDisplacementScale;",
				"uniform float uDisplacementBias;",
			"#endif",
			"varying vec3 vTangent;",
			"varying vec3 vBinormal;",
			"varying vec3 vNormal;",
			"varying vec2 vUv;",
			"varying vec3 vWorldPosition;",
			"varying vec3 vViewPosition;",
			THREE.ShaderChunk[ "skinning_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "skinbase_vertex" ],
				THREE.ShaderChunk[ "skinnormal_vertex" ],
								"#ifdef USE_SKINNING",
					"vNormal = normalize( normalMatrix * skinnedNormal.xyz );",
					"vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );",
					"vTangent = normalize( normalMatrix * skinnedTangent.xyz );",
				"#else",
					"vNormal = normalize( normalMatrix * normal );",
					"vTangent = normalize( normalMatrix * tangent.xyz );",
				"#endif",
				"vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );",
				"vUv = uv * uRepeat + uOffset;",
								"vec3 displacedPosition;",
				"#ifdef VERTEX_TEXTURES",
					"if ( enableDisplacement ) {",
						"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
						"float df = uDisplacementScale * dv.x + uDisplacementBias;",
						"displacedPosition = position + normalize( normal ) * df;",
					"} else {",
						"#ifdef USE_SKINNING",
							"vec4 skinVertex = vec4( position, 1.0 );",
							"vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
							"skinned 	  += boneMatY * skinVertex * skinWeight.y;",
							"displacedPosition  = skinned.xyz;",
						"#else",
							"displacedPosition = position;",
						"#endif",
					"}",
				"#else",
					"#ifdef USE_SKINNING",
						"vec4 skinVertex = vec4( position, 1.0 );",
						"vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
						"skinned 	  += boneMatY * skinVertex * skinWeight.y;",
						"displacedPosition  = skinned.xyz;",
					"#else",
						"displacedPosition = position;",
					"#endif",
				"#endif",
								"vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );",
				"vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );",
				"gl_Position = projectionMatrix * mvPosition;",
								"vWorldPosition = worldPosition.xyz;",
				"vViewPosition = -mvPosition.xyz;",
								"#ifdef USE_SHADOWMAP",
					"for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
						"vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;",
					"}",
				"#endif",
			"}"
		].join("\n")
	},
	/* -------------------------------------------------------------------------
		 ------------------------------------------------------------------------- */
	'cube': {
		uniforms: { "tCube": { type: "t", value: null },
					"tFlip": { type: "f", value: -1 } },
		vertexShader: [
			"varying vec3 vWorldPosition;",
			"void main() {",
				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
				"vWorldPosition = worldPosition.xyz;",
				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
			"}"
		].join("\n"),
		fragmentShader: [
			"uniform samplerCube tCube;",
			"uniform float tFlip;",
			"varying vec3 vWorldPosition;",
			"void main() {",
				"gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",
			"}"
		].join("\n")
	},
								'depthRGBA': {
		uniforms: {},
		vertexShader: [
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "skinning_pars_vertex" ],
			"void main() {",
				THREE.ShaderChunk[ "skinbase_vertex" ],
				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
			"}"
		].join("\n"),
		fragmentShader: [
			"vec4 pack_depth( const in float depth ) {",
				"const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );",
				"const vec4 bit_mask  = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );",
				"vec4 res = fract( depth * bit_shift );",
				"res -= res.xxyz * bit_mask;",
				"return res;",
			"}",
			"void main() {",
				"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );",
																			"}"
		].join("\n")
	}
};
THREE.WebGLRenderer = function ( parameters ) {
	console.log( 'THREE.WebGLRenderer', THREE.REVISION );
	parameters = parameters || {};
	var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
	_precision = parameters.precision !== undefined ? parameters.precision : 'highp',
	_alpha = parameters.alpha !== undefined ? parameters.alpha : true,
	_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
	_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
	_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
	_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
	_clearColor = new THREE.Color( 0x000000 ),
	_clearAlpha = 0;
	if ( parameters.clearColor !== undefined ) {
		console.warn( 'DEPRECATED: clearColor in WebGLRenderer constructor parameters is being removed. Use .setClearColor() instead.' );
		_clearColor.setHex( parameters.clearColor );
	}
	if ( parameters.clearAlpha !== undefined ) {
		console.warn( 'DEPRECATED: clearAlpha in WebGLRenderer constructor parameters is being removed. Use .setClearColor() instead.' );
		_clearAlpha = parameters.clearAlpha;
	}
		this.domElement = _canvas;
	this.context = null;
	this.devicePixelRatio = parameters.devicePixelRatio !== undefined
				? parameters.devicePixelRatio
				: window.devicePixelRatio !== undefined
					? window.devicePixelRatio
					: 1;
		this.autoClear = true;
	this.autoClearColor = true;
	this.autoClearDepth = true;
	this.autoClearStencil = true;
		this.sortObjects = true;
	this.autoUpdateObjects = true;
		this.gammaInput = false;
	this.gammaOutput = false;
	this.physicallyBasedShading = false;
		this.shadowMapEnabled = false;
	this.shadowMapAutoUpdate = true;
	this.shadowMapType = THREE.PCFShadowMap;
	this.shadowMapCullFace = THREE.CullFaceFront;
	this.shadowMapDebug = false;
	this.shadowMapCascade = false;
		this.maxMorphTargets = 8;
	this.maxMorphNormals = 4;
		this.autoScaleCubemaps = true;
		this.renderPluginsPre = [];
	this.renderPluginsPost = [];
		this.info = {
		memory: {
			programs: 0,
			geometries: 0,
			textures: 0
		},
		render: {
			calls: 0,
			vertices: 0,
			faces: 0,
			points: 0
		}
	};
		var _this = this,
	_programs = [],
	_programs_counter = 0,
		_currentProgram = null,
	_currentFramebuffer = null,
	_currentMaterialId = -1,
	_currentGeometryGroupHash = null,
	_currentCamera = null,
	_geometryGroupCounter = 0,
	_usedTextureUnits = 0,
		_oldDoubleSided = -1,
	_oldFlipSided = -1,
	_oldBlending = -1,
	_oldBlendEquation = -1,
	_oldBlendSrc = -1,
	_oldBlendDst = -1,
	_oldDepthTest = -1,
	_oldDepthWrite = -1,
	_oldPolygonOffset = null,
	_oldPolygonOffsetFactor = null,
	_oldPolygonOffsetUnits = null,
	_oldLineWidth = null,
	_viewportX = 0,
	_viewportY = 0,
	_viewportWidth = 0,
	_viewportHeight = 0,
	_currentWidth = 0,
	_currentHeight = 0,
	_enabledAttributes = {},
		_frustum = new THREE.Frustum(),
	 	_projScreenMatrix = new THREE.Matrix4(),
	_projScreenMatrixPS = new THREE.Matrix4(),
	_vector3 = new THREE.Vector3(),
		_direction = new THREE.Vector3(),
	_lightsNeedUpdate = true,
	_lights = {
		ambient: [ 0, 0, 0 ],
		directional: { length: 0, colors: new Array(), positions: new Array() },
		point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() },
		spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() },
		hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }
	};
		var _gl;
	var _glExtensionTextureFloat;
	var _glExtensionTextureFloatLinear;
	var _glExtensionStandardDerivatives;
	var _glExtensionTextureFilterAnisotropic;
	var _glExtensionCompressedTextureS3TC;
	initGL();
	setDefaultGLState();
	this.context = _gl;
		var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
	var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
	var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
	var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
	var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
	var _supportsVertexTextures = ( _maxVertexTextures > 0 );
	var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
	var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
		var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
	var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
	var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
	var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
	var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
	var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
	var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT );
	var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT );
	var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT );
	var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT );
	var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT );
	var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT );
		var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
	var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
	if ( _precision === "highp" && ! highpAvailable ) {
		if ( mediumpAvailable ) {
			_precision = "mediump";
			console.warn( "WebGLRenderer: highp not supported, using mediump" );
		} else {
			_precision = "lowp";
			console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" );
		}
	}
	if ( _precision === "mediump" && ! mediumpAvailable ) {
		_precision = "lowp";
		console.warn( "WebGLRenderer: mediump not supported, using lowp" );
	}
		this.getContext = function () {
		return _gl;
	};
	this.supportsVertexTextures = function () {
		return _supportsVertexTextures;
	};
	this.supportsFloatTextures = function () {
		return _glExtensionTextureFloat;
	};
	this.supportsStandardDerivatives = function () {
		return _glExtensionStandardDerivatives;
	};
	this.supportsCompressedTextureS3TC = function () {
		return _glExtensionCompressedTextureS3TC;
	};
	this.getMaxAnisotropy  = function () {
		return _maxAnisotropy;
	};
	this.getPrecision = function () {
		return _precision;
	};
	this.setSize = function ( width, height, updateStyle ) {
		_canvas.width = width * this.devicePixelRatio;
		_canvas.height = height * this.devicePixelRatio;
		if ( this.devicePixelRatio !== 1 && updateStyle !== false ) {
			_canvas.style.width = width + 'px';
			_canvas.style.height = height + 'px';
		}
		this.setViewport( 0, 0, _canvas.width, _canvas.height );
	};
	this.setViewport = function ( x, y, width, height ) {
		_viewportX = x !== undefined ? x : 0;
		_viewportY = y !== undefined ? y : 0;
		_viewportWidth = width !== undefined ? width : _canvas.width;
		_viewportHeight = height !== undefined ? height : _canvas.height;
		_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
	};
	this.setScissor = function ( x, y, width, height ) {
		_gl.scissor( x, y, width, height );
	};
	this.enableScissorTest = function ( enable ) {
		enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );
	};
		this.setClearColor = function ( color, alpha ) {
		_clearColor.set( color );
		_clearAlpha = alpha !== undefined ? alpha : 1;
		_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
	};
	this.setClearColorHex = function ( hex, alpha ) {
		console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
		this.setClearColor( hex, alpha );
	};
	this.getClearColor = function () {
		return _clearColor;
	};
	this.getClearAlpha = function () {
		return _clearAlpha;
	};
	this.clear = function ( color, depth, stencil ) {
		var bits = 0;
		if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
		if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
		if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
		_gl.clear( bits );
	};
	this.clearTarget = function ( renderTarget, color, depth, stencil ) {
		this.setRenderTarget( renderTarget );
		this.clear( color, depth, stencil );
	};
		this.addPostPlugin = function ( plugin ) {
		plugin.init( this );
		this.renderPluginsPost.push( plugin );
	};
	this.addPrePlugin = function ( plugin ) {
		plugin.init( this );
		this.renderPluginsPre.push( plugin );
	};
		this.updateShadowMap = function ( scene, camera ) {
		_currentProgram = null;
		_oldBlending = -1;
		_oldDepthTest = -1;
		_oldDepthWrite = -1;
		_currentGeometryGroupHash = -1;
		_currentMaterialId = -1;
		_lightsNeedUpdate = true;
		_oldDoubleSided = -1;
		_oldFlipSided = -1;
		this.shadowMapPlugin.update( scene, camera );
	};
			function createParticleBuffers ( geometry ) {
		geometry.__webglVertexBuffer = _gl.createBuffer();
		geometry.__webglColorBuffer = _gl.createBuffer();
		_this.info.memory.geometries ++;
	};
	function createLineBuffers ( geometry ) {
		geometry.__webglVertexBuffer = _gl.createBuffer();
		geometry.__webglColorBuffer = _gl.createBuffer();
		geometry.__webglLineDistanceBuffer = _gl.createBuffer();
		_this.info.memory.geometries ++;
	};
	function createRibbonBuffers ( geometry ) {
		geometry.__webglVertexBuffer = _gl.createBuffer();
		geometry.__webglColorBuffer = _gl.createBuffer();
		geometry.__webglNormalBuffer = _gl.createBuffer();
		_this.info.memory.geometries ++;
	};
	function createMeshBuffers ( geometryGroup ) {
		geometryGroup.__webglVertexBuffer = _gl.createBuffer();
		geometryGroup.__webglNormalBuffer = _gl.createBuffer();
		geometryGroup.__webglTangentBuffer = _gl.createBuffer();
		geometryGroup.__webglColorBuffer = _gl.createBuffer();
		geometryGroup.__webglUVBuffer = _gl.createBuffer();
		geometryGroup.__webglUV2Buffer = _gl.createBuffer();
		geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
		geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();
		geometryGroup.__webglFaceBuffer = _gl.createBuffer();
		geometryGroup.__webglLineBuffer = _gl.createBuffer();
		var m, ml;
		if ( geometryGroup.numMorphTargets ) {
			geometryGroup.__webglMorphTargetsBuffers = [];
			for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
				geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );
			}
		}
		if ( geometryGroup.numMorphNormals ) {
			geometryGroup.__webglMorphNormalsBuffers = [];
			for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
				geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() );
			}
		}
		_this.info.memory.geometries ++;
	};
		var onGeometryDispose = function ( event ) {
		var geometry = event.target;
		geometry.removeEventListener( 'dispose', onGeometryDispose );
		deallocateGeometry( geometry );
		_this.info.memory.geometries --;
	};
	var onTextureDispose = function ( event ) {
		var texture = event.target;
		texture.removeEventListener( 'dispose', onTextureDispose );
		deallocateTexture( texture );
		_this.info.memory.textures --;
	};
	var onRenderTargetDispose = function ( event ) {
		var renderTarget = event.target;
		renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
		deallocateRenderTarget( renderTarget );
		_this.info.memory.textures --;
	};
	var onMaterialDispose = function ( event ) {
		var material = event.target;
		material.removeEventListener( 'dispose', onMaterialDispose );
		deallocateMaterial( material );
	};
		var deallocateGeometry = function ( geometry ) {
		geometry.__webglInit = undefined;
		if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer );
		if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer );
		if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer );
		if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer );
		if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer );
		if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer );
		if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer );
		if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer );
		if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer );
		if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer );
		if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer );
				if ( geometry.geometryGroups !== undefined ) {
			for ( var g in geometry.geometryGroups ) {
				var geometryGroup = geometry.geometryGroups[ g ];
				if ( geometryGroup.numMorphTargets !== undefined ) {
					for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
						_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
					}
				}
				if ( geometryGroup.numMorphNormals !== undefined ) {
					for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
						_gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
					}
				}
				deleteCustomAttributesBuffers( geometryGroup );
			}
		}
		deleteCustomAttributesBuffers( geometry );
	};
	var deallocateTexture = function ( texture ) {
		if ( texture.image && texture.image.__webglTextureCube ) {
						_gl.deleteTexture( texture.image.__webglTextureCube );
		} else {
						if ( ! texture.__webglInit ) return;
			texture.__webglInit = false;
			_gl.deleteTexture( texture.__webglTexture );
		}
	};
	var deallocateRenderTarget = function ( renderTarget ) {
		if ( !renderTarget || ! renderTarget.__webglTexture ) return;
		_gl.deleteTexture( renderTarget.__webglTexture );
		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
			for ( var i = 0; i < 6; i ++ ) {
				_gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
				_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
			}
		} else {
			_gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
			_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
		}
	};
	var deallocateMaterial = function ( material ) {
		var program = material.program;
		if ( program === undefined ) return;
		material.program = undefined;
								var i, il, programInfo;
		var deleteProgram = false;
		for ( i = 0, il = _programs.length; i < il; i ++ ) {
			programInfo = _programs[ i ];
			if ( programInfo.program === program ) {
				programInfo.usedTimes --;
				if ( programInfo.usedTimes === 0 ) {
					deleteProgram = true;
				}
				break;
			}
		}
		if ( deleteProgram === true ) {
						var newPrograms = [];
			for ( i = 0, il = _programs.length; i < il; i ++ ) {
				programInfo = _programs[ i ];
				if ( programInfo.program !== program ) {
					newPrograms.push( programInfo );
				}
			}
			_programs = newPrograms;
			_gl.deleteProgram( program );
			_this.info.memory.programs --;
		}
	};
		function deleteCustomAttributesBuffers( geometry ) {
		if ( geometry.__webglCustomAttributesList ) {
			for ( var id in geometry.__webglCustomAttributesList ) {
				_gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer );
			}
		}
	};
		function initCustomAttributes ( geometry, object ) {
		var nvertices = geometry.vertices.length;
		var material = object.material;
		if ( material.attributes ) {
			if ( geometry.__webglCustomAttributesList === undefined ) {
				geometry.__webglCustomAttributesList = [];
			}
			for ( var a in material.attributes ) {
				var attribute = material.attributes[ a ];
				if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
					attribute.__webglInitialized = true;
					var size = 1;							if ( attribute.type === "v2" ) size = 2;
					else if ( attribute.type === "v3" ) size = 3;
					else if ( attribute.type === "v4" ) size = 4;
					else if ( attribute.type === "c"  ) size = 3;
					attribute.size = size;
					attribute.array = new Float32Array( nvertices * size );
					attribute.buffer = _gl.createBuffer();
					attribute.buffer.belongsToAttribute = a;
					attribute.needsUpdate = true;
				}
				geometry.__webglCustomAttributesList.push( attribute );
			}
		}
	};
	function initParticleBuffers ( geometry, object ) {
		var nvertices = geometry.vertices.length;
		geometry.__vertexArray = new Float32Array( nvertices * 3 );
		geometry.__colorArray = new Float32Array( nvertices * 3 );
		geometry.__sortArray = [];
		geometry.__webglParticleCount = nvertices;
		initCustomAttributes ( geometry, object );
	};
	function initLineBuffers ( geometry, object ) {
		var nvertices = geometry.vertices.length;
		geometry.__vertexArray = new Float32Array( nvertices * 3 );
		geometry.__colorArray = new Float32Array( nvertices * 3 );
		geometry.__lineDistanceArray = new Float32Array( nvertices * 1 );
		geometry.__webglLineCount = nvertices;
		initCustomAttributes ( geometry, object );
	};
	function initRibbonBuffers ( geometry, object ) {
		var nvertices = geometry.vertices.length;
		geometry.__vertexArray = new Float32Array( nvertices * 3 );
		geometry.__colorArray = new Float32Array( nvertices * 3 );
		geometry.__normalArray = new Float32Array( nvertices * 3 );
		geometry.__webglVertexCount = nvertices;
		initCustomAttributes ( geometry, object );
	};
	function initMeshBuffers ( geometryGroup, object ) {
		var geometry = object.geometry,
			faces3 = geometryGroup.faces3,
			faces4 = geometryGroup.faces4,
			nvertices = faces3.length * 3 + faces4.length * 4,
			ntris     = faces3.length * 1 + faces4.length * 2,
			nlines    = faces3.length * 3 + faces4.length * 4,
			material = getBufferMaterial( object, geometryGroup ),
			uvType = bufferGuessUVType( material ),
			normalType = bufferGuessNormalType( material ),
			vertexColorType = bufferGuessVertexColorType( material );
				geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
		if ( normalType ) {
			geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
		}
		if ( geometry.hasTangents ) {
			geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
		}
		if ( vertexColorType ) {
			geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
		}
		if ( uvType ) {
			if ( geometry.faceUvs.length > 0 || geometry.faceVertexUvs.length > 0 ) {
				geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
			}
			if ( geometry.faceUvs.length > 1 || geometry.faceVertexUvs.length > 1 ) {
				geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
			}
		}
		if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
			geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
			geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
		}
		geometryGroup.__faceArray = new Uint16Array( ntris * 3 );
		geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
		var m, ml;
		if ( geometryGroup.numMorphTargets ) {
			geometryGroup.__morphTargetsArrays = [];
			for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
				geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );
			}
		}
		if ( geometryGroup.numMorphNormals ) {
			geometryGroup.__morphNormalsArrays = [];
			for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
				geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) );
			}
		}
		geometryGroup.__webglFaceCount = ntris * 3;
		geometryGroup.__webglLineCount = nlines * 2;
				if ( material.attributes ) {
			if ( geometryGroup.__webglCustomAttributesList === undefined ) {
				geometryGroup.__webglCustomAttributesList = [];
			}
			for ( var a in material.attributes ) {
												var originalAttribute = material.attributes[ a ];
				var attribute = {};
				for ( var property in originalAttribute ) {
					attribute[ property ] = originalAttribute[ property ];
				}
				if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
					attribute.__webglInitialized = true;
					var size = 1;							if( attribute.type === "v2" ) size = 2;
					else if( attribute.type === "v3" ) size = 3;
					else if( attribute.type === "v4" ) size = 4;
					else if( attribute.type === "c"  ) size = 3;
					attribute.size = size;
					attribute.array = new Float32Array( nvertices * size );
					attribute.buffer = _gl.createBuffer();
					attribute.buffer.belongsToAttribute = a;
					originalAttribute.needsUpdate = true;
					attribute.__original = originalAttribute;
				}
				geometryGroup.__webglCustomAttributesList.push( attribute );
			}
		}
		geometryGroup.__inittedArrays = true;
	};
	function getBufferMaterial( object, geometryGroup ) {
		return object.material instanceof THREE.MeshFaceMaterial
			? object.material.materials[ geometryGroup.materialIndex ]
			: object.material;
	};
	function materialNeedsSmoothNormals ( material ) {
		return material && material.shading !== undefined && material.shading === THREE.SmoothShading;
	};
	function bufferGuessNormalType ( material ) {
				if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) ) {
			return false;
		}
		if ( materialNeedsSmoothNormals( material ) ) {
			return THREE.SmoothShading;
		} else {
			return THREE.FlatShading;
		}
	};
	function bufferGuessVertexColorType( material ) {
		if ( material.vertexColors ) {
			return material.vertexColors;
		}
		return false;
	};
	function bufferGuessUVType( material ) {
				if ( material.map ||
		     material.lightMap ||
		     material.bumpMap ||
		     material.normalMap ||
		     material.specularMap ||
		     material instanceof THREE.ShaderMaterial ) {
			return true;
		}
		return false;
	};
		function initDirectBuffers( geometry ) {
		var a, attribute, type;
		for ( a in geometry.attributes ) {
			if ( a === "index" ) {
				type = _gl.ELEMENT_ARRAY_BUFFER;
			} else {
				type = _gl.ARRAY_BUFFER;
			}
			attribute = geometry.attributes[ a ];
			if ( attribute.numItems === undefined ) {
				attribute.numItems = attribute.array.length;
			}
			attribute.buffer = _gl.createBuffer();
			_gl.bindBuffer( type, attribute.buffer );
			_gl.bufferData( type, attribute.array, _gl.STATIC_DRAW );
		}
	};
		function setParticleBuffers ( geometry, hint, object ) {
		var v, c, vertex, offset, index, color,
		vertices = geometry.vertices,
		vl = vertices.length,
		colors = geometry.colors,
		cl = colors.length,
		vertexArray = geometry.__vertexArray,
		colorArray = geometry.__colorArray,
		sortArray = geometry.__sortArray,
		dirtyVertices = geometry.verticesNeedUpdate,
		dirtyElements = geometry.elementsNeedUpdate,
		dirtyColors = geometry.colorsNeedUpdate,
		customAttributes = geometry.__webglCustomAttributesList,
		i, il,
		a, ca, cal, value,
		customAttribute;
		if ( object.sortParticles ) {
			_projScreenMatrixPS.copy( _projScreenMatrix );
			_projScreenMatrixPS.multiply( object.matrixWorld );
			for ( v = 0; v < vl; v ++ ) {
				vertex = vertices[ v ];
				_vector3.copy( vertex );
				_vector3.applyProjection( _projScreenMatrixPS );
				sortArray[ v ] = [ _vector3.z, v ];
			}
			sortArray.sort( numericalSort );
			for ( v = 0; v < vl; v ++ ) {
				vertex = vertices[ sortArray[v][1] ];
				offset = v * 3;
				vertexArray[ offset ]     = vertex.x;
				vertexArray[ offset + 1 ] = vertex.y;
				vertexArray[ offset + 2 ] = vertex.z;
			}
			for ( c = 0; c < cl; c ++ ) {
				offset = c * 3;
				color = colors[ sortArray[c][1] ];
				colorArray[ offset ]     = color.r;
				colorArray[ offset + 1 ] = color.g;
				colorArray[ offset + 2 ] = color.b;
			}
			if ( customAttributes ) {
				for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
					customAttribute = customAttributes[ i ];
					if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue;
					offset = 0;
					cal = customAttribute.value.length;
					if ( customAttribute.size === 1 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							index = sortArray[ ca ][ 1 ];
							customAttribute.array[ ca ] = customAttribute.value[ index ];
						}
					} else if ( customAttribute.size === 2 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							index = sortArray[ ca ][ 1 ];
							value = customAttribute.value[ index ];
							customAttribute.array[ offset ] 	= value.x;
							customAttribute.array[ offset + 1 ] = value.y;
							offset += 2;
						}
					} else if ( customAttribute.size === 3 ) {
						if ( customAttribute.type === "c" ) {
							for ( ca = 0; ca < cal; ca ++ ) {
								index = sortArray[ ca ][ 1 ];
								value = customAttribute.value[ index ];
								customAttribute.array[ offset ]     = value.r;
								customAttribute.array[ offset + 1 ] = value.g;
								customAttribute.array[ offset + 2 ] = value.b;
								offset += 3;
							}
						} else {
							for ( ca = 0; ca < cal; ca ++ ) {
								index = sortArray[ ca ][ 1 ];
								value = customAttribute.value[ index ];
								customAttribute.array[ offset ] 	= value.x;
								customAttribute.array[ offset + 1 ] = value.y;
								customAttribute.array[ offset + 2 ] = value.z;
								offset += 3;
							}
						}
					} else if ( customAttribute.size === 4 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							index = sortArray[ ca ][ 1 ];
							value = customAttribute.value[ index ];
							customAttribute.array[ offset ]      = value.x;
							customAttribute.array[ offset + 1  ] = value.y;
							customAttribute.array[ offset + 2  ] = value.z;
							customAttribute.array[ offset + 3  ] = value.w;
							offset += 4;
						}
					}
				}
			}
		} else {
			if ( dirtyVertices ) {
				for ( v = 0; v < vl; v ++ ) {
					vertex = vertices[ v ];
					offset = v * 3;
					vertexArray[ offset ]     = vertex.x;
					vertexArray[ offset + 1 ] = vertex.y;
					vertexArray[ offset + 2 ] = vertex.z;
				}
			}
			if ( dirtyColors ) {
				for ( c = 0; c < cl; c ++ ) {
					color = colors[ c ];
					offset = c * 3;
					colorArray[ offset ]     = color.r;
					colorArray[ offset + 1 ] = color.g;
					colorArray[ offset + 2 ] = color.b;
				}
			}
			if ( customAttributes ) {
				for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
					customAttribute = customAttributes[ i ];
					if ( customAttribute.needsUpdate &&
						 ( customAttribute.boundTo === undefined ||
						   customAttribute.boundTo === "vertices") ) {
						cal = customAttribute.value.length;
						offset = 0;
						if ( customAttribute.size === 1 ) {
							for ( ca = 0; ca < cal; ca ++ ) {
								customAttribute.array[ ca ] = customAttribute.value[ ca ];
							}
						} else if ( customAttribute.size === 2 ) {
							for ( ca = 0; ca < cal; ca ++ ) {
								value = customAttribute.value[ ca ];
								customAttribute.array[ offset ] 	= value.x;
								customAttribute.array[ offset + 1 ] = value.y;
								offset += 2;
							}
						} else if ( customAttribute.size === 3 ) {
							if ( customAttribute.type === "c" ) {
								for ( ca = 0; ca < cal; ca ++ ) {
									value = customAttribute.value[ ca ];
									customAttribute.array[ offset ] 	= value.r;
									customAttribute.array[ offset + 1 ] = value.g;
									customAttribute.array[ offset + 2 ] = value.b;
									offset += 3;
								}
							} else {
								for ( ca = 0; ca < cal; ca ++ ) {
									value = customAttribute.value[ ca ];
									customAttribute.array[ offset ] 	= value.x;
									customAttribute.array[ offset + 1 ] = value.y;
									customAttribute.array[ offset + 2 ] = value.z;
									offset += 3;
								}
							}
						} else if ( customAttribute.size === 4 ) {
							for ( ca = 0; ca < cal; ca ++ ) {
								value = customAttribute.value[ ca ];
								customAttribute.array[ offset ]      = value.x;
								customAttribute.array[ offset + 1  ] = value.y;
								customAttribute.array[ offset + 2  ] = value.z;
								customAttribute.array[ offset + 3  ] = value.w;
								offset += 4;
							}
						}
					}
				}
			}
		}
		if ( dirtyVertices || object.sortParticles ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
		}
		if ( dirtyColors || object.sortParticles ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
		}
		if ( customAttributes ) {
			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
				customAttribute = customAttributes[ i ];
				if ( customAttribute.needsUpdate || object.sortParticles ) {
					_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
					_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
				}
			}
		}
	};
	function setLineBuffers ( geometry, hint ) {
		var v, c, d, vertex, offset, color,
		vertices = geometry.vertices,
		colors = geometry.colors,
		lineDistances = geometry.lineDistances,
		vl = vertices.length,
		cl = colors.length,
		dl = lineDistances.length,
		vertexArray = geometry.__vertexArray,
		colorArray = geometry.__colorArray,
		lineDistanceArray = geometry.__lineDistanceArray,
		dirtyVertices = geometry.verticesNeedUpdate,
		dirtyColors = geometry.colorsNeedUpdate,
		dirtyLineDistances = geometry.lineDistancesNeedUpdate,
		customAttributes = geometry.__webglCustomAttributesList,
		i, il,
		a, ca, cal, value,
		customAttribute;
		if ( dirtyVertices ) {
			for ( v = 0; v < vl; v ++ ) {
				vertex = vertices[ v ];
				offset = v * 3;
				vertexArray[ offset ]     = vertex.x;
				vertexArray[ offset + 1 ] = vertex.y;
				vertexArray[ offset + 2 ] = vertex.z;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
		}
		if ( dirtyColors ) {
			for ( c = 0; c < cl; c ++ ) {
				color = colors[ c ];
				offset = c * 3;
				colorArray[ offset ]     = color.r;
				colorArray[ offset + 1 ] = color.g;
				colorArray[ offset + 2 ] = color.b;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
		}
		if ( dirtyLineDistances ) {
			for ( d = 0; d < dl; d ++ ) {
				lineDistanceArray[ d ] = lineDistances[ d ];
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint );
		}
		if ( customAttributes ) {
			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
				customAttribute = customAttributes[ i ];
				if ( customAttribute.needsUpdate &&
					 ( customAttribute.boundTo === undefined ||
					   customAttribute.boundTo === "vertices" ) ) {
					offset = 0;
					cal = customAttribute.value.length;
					if ( customAttribute.size === 1 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							customAttribute.array[ ca ] = customAttribute.value[ ca ];
						}
					} else if ( customAttribute.size === 2 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							value = customAttribute.value[ ca ];
							customAttribute.array[ offset ] 	= value.x;
							customAttribute.array[ offset + 1 ] = value.y;
							offset += 2;
						}
					} else if ( customAttribute.size === 3 ) {
						if ( customAttribute.type === "c" ) {
							for ( ca = 0; ca < cal; ca ++ ) {
								value = customAttribute.value[ ca ];
								customAttribute.array[ offset ] 	= value.r;
								customAttribute.array[ offset + 1 ] = value.g;
								customAttribute.array[ offset + 2 ] = value.b;
								offset += 3;
							}
						} else {
							for ( ca = 0; ca < cal; ca ++ ) {
								value = customAttribute.value[ ca ];
								customAttribute.array[ offset ] 	= value.x;
								customAttribute.array[ offset + 1 ] = value.y;
								customAttribute.array[ offset + 2 ] = value.z;
								offset += 3;
							}
						}
					} else if ( customAttribute.size === 4 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							value = customAttribute.value[ ca ];
							customAttribute.array[ offset ] 	 = value.x;
							customAttribute.array[ offset + 1  ] = value.y;
							customAttribute.array[ offset + 2  ] = value.z;
							customAttribute.array[ offset + 3  ] = value.w;
							offset += 4;
						}
					}
					_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
					_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
				}
			}
		}
	};
	function setRibbonBuffers ( geometry, hint ) {
		var v, c, n, vertex, offset, color, normal,
		i, il, ca, cal, customAttribute, value,
		vertices = geometry.vertices,
		colors = geometry.colors,
		normals = geometry.normals,
		vl = vertices.length,
		cl = colors.length,
		nl = normals.length,
		vertexArray = geometry.__vertexArray,
		colorArray = geometry.__colorArray,
		normalArray = geometry.__normalArray,
		dirtyVertices = geometry.verticesNeedUpdate,
		dirtyColors = geometry.colorsNeedUpdate,
		dirtyNormals = geometry.normalsNeedUpdate,
		customAttributes = geometry.__webglCustomAttributesList;
		if ( dirtyVertices ) {
			for ( v = 0; v < vl; v ++ ) {
				vertex = vertices[ v ];
				offset = v * 3;
				vertexArray[ offset ]     = vertex.x;
				vertexArray[ offset + 1 ] = vertex.y;
				vertexArray[ offset + 2 ] = vertex.z;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
		}
		if ( dirtyColors ) {
			for ( c = 0; c < cl; c ++ ) {
				color = colors[ c ];
				offset = c * 3;
				colorArray[ offset ]     = color.r;
				colorArray[ offset + 1 ] = color.g;
				colorArray[ offset + 2 ] = color.b;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
		}
		if ( dirtyNormals ) {
			for ( n = 0; n < nl; n ++ ) {
				normal = normals[ n ];
				offset = n * 3;
				normalArray[ offset ]     = normal.x;
				normalArray[ offset + 1 ] = normal.y;
				normalArray[ offset + 2 ] = normal.z;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglNormalBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
		}
		if ( customAttributes ) {
			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
				customAttribute = customAttributes[ i ];
				if ( customAttribute.needsUpdate &&
					 ( customAttribute.boundTo === undefined ||
					   customAttribute.boundTo === "vertices" ) ) {
					offset = 0;
					cal = customAttribute.value.length;
					if ( customAttribute.size === 1 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							customAttribute.array[ ca ] = customAttribute.value[ ca ];
						}
					} else if ( customAttribute.size === 2 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							value = customAttribute.value[ ca ];
							customAttribute.array[ offset ] 	= value.x;
							customAttribute.array[ offset + 1 ] = value.y;
							offset += 2;
						}
					} else if ( customAttribute.size === 3 ) {
						if ( customAttribute.type === "c" ) {
							for ( ca = 0; ca < cal; ca ++ ) {
								value = customAttribute.value[ ca ];
								customAttribute.array[ offset ] 	= value.r;
								customAttribute.array[ offset + 1 ] = value.g;
								customAttribute.array[ offset + 2 ] = value.b;
								offset += 3;
							}
						} else {
							for ( ca = 0; ca < cal; ca ++ ) {
								value = customAttribute.value[ ca ];
								customAttribute.array[ offset ] 	= value.x;
								customAttribute.array[ offset + 1 ] = value.y;
								customAttribute.array[ offset + 2 ] = value.z;
								offset += 3;
							}
						}
					} else if ( customAttribute.size === 4 ) {
						for ( ca = 0; ca < cal; ca ++ ) {
							value = customAttribute.value[ ca ];
							customAttribute.array[ offset ] 	 = value.x;
							customAttribute.array[ offset + 1  ] = value.y;
							customAttribute.array[ offset + 2  ] = value.z;
							customAttribute.array[ offset + 3  ] = value.w;
							offset += 4;
						}
					}
					_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
					_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
				}
			}
		}
	};
	function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {
		if ( ! geometryGroup.__inittedArrays ) {
			return;
		}
		var normalType = bufferGuessNormalType( material ),
		vertexColorType = bufferGuessVertexColorType( material ),
		uvType = bufferGuessUVType( material ),
		needsSmoothNormals = ( normalType === THREE.SmoothShading );
		var f, fl, fi, face,
		vertexNormals, faceNormal, normal,
		vertexColors, faceColor,
		vertexTangents,
		uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4,
		c1, c2, c3, c4,
		sw1, sw2, sw3, sw4,
		si1, si2, si3, si4,
		sa1, sa2, sa3, sa4,
		sb1, sb2, sb3, sb4,
		m, ml, i, il,
		vn, uvi, uv2i,
		vk, vkl, vka,
		nka, chf, faceVertexNormals,
		a,
		vertexIndex = 0,
		offset = 0,
		offset_uv = 0,
		offset_uv2 = 0,
		offset_face = 0,
		offset_normal = 0,
		offset_tangent = 0,
		offset_line = 0,
		offset_color = 0,
		offset_skin = 0,
		offset_morphTarget = 0,
		offset_custom = 0,
		offset_customSrc = 0,
		value,
		vertexArray = geometryGroup.__vertexArray,
		uvArray = geometryGroup.__uvArray,
		uv2Array = geometryGroup.__uv2Array,
		normalArray = geometryGroup.__normalArray,
		tangentArray = geometryGroup.__tangentArray,
		colorArray = geometryGroup.__colorArray,
		skinIndexArray = geometryGroup.__skinIndexArray,
		skinWeightArray = geometryGroup.__skinWeightArray,
		morphTargetsArrays = geometryGroup.__morphTargetsArrays,
		morphNormalsArrays = geometryGroup.__morphNormalsArrays,
		customAttributes = geometryGroup.__webglCustomAttributesList,
		customAttribute,
		faceArray = geometryGroup.__faceArray,
		lineArray = geometryGroup.__lineArray,
		geometry = object.geometry, 		dirtyVertices = geometry.verticesNeedUpdate,
		dirtyElements = geometry.elementsNeedUpdate,
		dirtyUvs = geometry.uvsNeedUpdate,
		dirtyNormals = geometry.normalsNeedUpdate,
		dirtyTangents = geometry.tangentsNeedUpdate,
		dirtyColors = geometry.colorsNeedUpdate,
		dirtyMorphTargets = geometry.morphTargetsNeedUpdate,
		vertices = geometry.vertices,
		chunk_faces3 = geometryGroup.faces3,
		chunk_faces4 = geometryGroup.faces4,
		obj_faces = geometry.faces,
		obj_uvs  = geometry.faceVertexUvs[ 0 ],
		obj_uvs2 = geometry.faceVertexUvs[ 1 ],
		obj_colors = geometry.colors,
		obj_skinIndices = geometry.skinIndices,
		obj_skinWeights = geometry.skinWeights,
		morphTargets = geometry.morphTargets,
		morphNormals = geometry.morphNormals;
		if ( dirtyVertices ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces3[ f ] ];
				v1 = vertices[ face.a ];
				v2 = vertices[ face.b ];
				v3 = vertices[ face.c ];
				vertexArray[ offset ]     = v1.x;
				vertexArray[ offset + 1 ] = v1.y;
				vertexArray[ offset + 2 ] = v1.z;
				vertexArray[ offset + 3 ] = v2.x;
				vertexArray[ offset + 4 ] = v2.y;
				vertexArray[ offset + 5 ] = v2.z;
				vertexArray[ offset + 6 ] = v3.x;
				vertexArray[ offset + 7 ] = v3.y;
				vertexArray[ offset + 8 ] = v3.z;
				offset += 9;
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces4[ f ] ];
				v1 = vertices[ face.a ];
				v2 = vertices[ face.b ];
				v3 = vertices[ face.c ];
				v4 = vertices[ face.d ];
				vertexArray[ offset ]     = v1.x;
				vertexArray[ offset + 1 ] = v1.y;
				vertexArray[ offset + 2 ] = v1.z;
				vertexArray[ offset + 3 ] = v2.x;
				vertexArray[ offset + 4 ] = v2.y;
				vertexArray[ offset + 5 ] = v2.z;
				vertexArray[ offset + 6 ] = v3.x;
				vertexArray[ offset + 7 ] = v3.y;
				vertexArray[ offset + 8 ] = v3.z;
				vertexArray[ offset + 9 ]  = v4.x;
				vertexArray[ offset + 10 ] = v4.y;
				vertexArray[ offset + 11 ] = v4.z;
				offset += 12;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
		}
		if ( dirtyMorphTargets ) {
			for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
				offset_morphTarget = 0;
				for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
					chf = chunk_faces3[ f ];
					face = obj_faces[ chf ];
										v1 = morphTargets[ vk ].vertices[ face.a ];
					v2 = morphTargets[ vk ].vertices[ face.b ];
					v3 = morphTargets[ vk ].vertices[ face.c ];
					vka = morphTargetsArrays[ vk ];
					vka[ offset_morphTarget ] 	  = v1.x;
					vka[ offset_morphTarget + 1 ] = v1.y;
					vka[ offset_morphTarget + 2 ] = v1.z;
					vka[ offset_morphTarget + 3 ] = v2.x;
					vka[ offset_morphTarget + 4 ] = v2.y;
					vka[ offset_morphTarget + 5 ] = v2.z;
					vka[ offset_morphTarget + 6 ] = v3.x;
					vka[ offset_morphTarget + 7 ] = v3.y;
					vka[ offset_morphTarget + 8 ] = v3.z;
										if ( material.morphNormals ) {
						if ( needsSmoothNormals ) {
							faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
							n1 = faceVertexNormals.a;
							n2 = faceVertexNormals.b;
							n3 = faceVertexNormals.c;
						} else {
							n1 = morphNormals[ vk ].faceNormals[ chf ];
							n2 = n1;
							n3 = n1;
						}
						nka = morphNormalsArrays[ vk ];
						nka[ offset_morphTarget ] 	  = n1.x;
						nka[ offset_morphTarget + 1 ] = n1.y;
						nka[ offset_morphTarget + 2 ] = n1.z;
						nka[ offset_morphTarget + 3 ] = n2.x;
						nka[ offset_morphTarget + 4 ] = n2.y;
						nka[ offset_morphTarget + 5 ] = n2.z;
						nka[ offset_morphTarget + 6 ] = n3.x;
						nka[ offset_morphTarget + 7 ] = n3.y;
						nka[ offset_morphTarget + 8 ] = n3.z;
					}
										offset_morphTarget += 9;
				}
				for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
					chf = chunk_faces4[ f ];
					face = obj_faces[ chf ];
										v1 = morphTargets[ vk ].vertices[ face.a ];
					v2 = morphTargets[ vk ].vertices[ face.b ];
					v3 = morphTargets[ vk ].vertices[ face.c ];
					v4 = morphTargets[ vk ].vertices[ face.d ];
					vka = morphTargetsArrays[ vk ];
					vka[ offset_morphTarget ] 	  = v1.x;
					vka[ offset_morphTarget + 1 ] = v1.y;
					vka[ offset_morphTarget + 2 ] = v1.z;
					vka[ offset_morphTarget + 3 ] = v2.x;
					vka[ offset_morphTarget + 4 ] = v2.y;
					vka[ offset_morphTarget + 5 ] = v2.z;
					vka[ offset_morphTarget + 6 ] = v3.x;
					vka[ offset_morphTarget + 7 ] = v3.y;
					vka[ offset_morphTarget + 8 ] = v3.z;
					vka[ offset_morphTarget + 9 ]  = v4.x;
					vka[ offset_morphTarget + 10 ] = v4.y;
					vka[ offset_morphTarget + 11 ] = v4.z;
										if ( material.morphNormals ) {
						if ( needsSmoothNormals ) {
							faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
							n1 = faceVertexNormals.a;
							n2 = faceVertexNormals.b;
							n3 = faceVertexNormals.c;
							n4 = faceVertexNormals.d;
						} else {
							n1 = morphNormals[ vk ].faceNormals[ chf ];
							n2 = n1;
							n3 = n1;
							n4 = n1;
						}
						nka = morphNormalsArrays[ vk ];
						nka[ offset_morphTarget ] 	  = n1.x;
						nka[ offset_morphTarget + 1 ] = n1.y;
						nka[ offset_morphTarget + 2 ] = n1.z;
						nka[ offset_morphTarget + 3 ] = n2.x;
						nka[ offset_morphTarget + 4 ] = n2.y;
						nka[ offset_morphTarget + 5 ] = n2.z;
						nka[ offset_morphTarget + 6 ] = n3.x;
						nka[ offset_morphTarget + 7 ] = n3.y;
						nka[ offset_morphTarget + 8 ] = n3.z;
						nka[ offset_morphTarget + 9 ]  = n4.x;
						nka[ offset_morphTarget + 10 ] = n4.y;
						nka[ offset_morphTarget + 11 ] = n4.z;
					}
										offset_morphTarget += 12;
				}
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
				_gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
				if ( material.morphNormals ) {
					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );
					_gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );
				}
			}
		}
		if ( obj_skinWeights.length ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces3[ f ]	];
								sw1 = obj_skinWeights[ face.a ];
				sw2 = obj_skinWeights[ face.b ];
				sw3 = obj_skinWeights[ face.c ];
				skinWeightArray[ offset_skin ]     = sw1.x;
				skinWeightArray[ offset_skin + 1 ] = sw1.y;
				skinWeightArray[ offset_skin + 2 ] = sw1.z;
				skinWeightArray[ offset_skin + 3 ] = sw1.w;
				skinWeightArray[ offset_skin + 4 ] = sw2.x;
				skinWeightArray[ offset_skin + 5 ] = sw2.y;
				skinWeightArray[ offset_skin + 6 ] = sw2.z;
				skinWeightArray[ offset_skin + 7 ] = sw2.w;
				skinWeightArray[ offset_skin + 8 ]  = sw3.x;
				skinWeightArray[ offset_skin + 9 ]  = sw3.y;
				skinWeightArray[ offset_skin + 10 ] = sw3.z;
				skinWeightArray[ offset_skin + 11 ] = sw3.w;
								si1 = obj_skinIndices[ face.a ];
				si2 = obj_skinIndices[ face.b ];
				si3 = obj_skinIndices[ face.c ];
				skinIndexArray[ offset_skin ]     = si1.x;
				skinIndexArray[ offset_skin + 1 ] = si1.y;
				skinIndexArray[ offset_skin + 2 ] = si1.z;
				skinIndexArray[ offset_skin + 3 ] = si1.w;
				skinIndexArray[ offset_skin + 4 ] = si2.x;
				skinIndexArray[ offset_skin + 5 ] = si2.y;
				skinIndexArray[ offset_skin + 6 ] = si2.z;
				skinIndexArray[ offset_skin + 7 ] = si2.w;
				skinIndexArray[ offset_skin + 8 ]  = si3.x;
				skinIndexArray[ offset_skin + 9 ]  = si3.y;
				skinIndexArray[ offset_skin + 10 ] = si3.z;
				skinIndexArray[ offset_skin + 11 ] = si3.w;
				offset_skin += 12;
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces4[ f ] ];
								sw1 = obj_skinWeights[ face.a ];
				sw2 = obj_skinWeights[ face.b ];
				sw3 = obj_skinWeights[ face.c ];
				sw4 = obj_skinWeights[ face.d ];
				skinWeightArray[ offset_skin ]     = sw1.x;
				skinWeightArray[ offset_skin + 1 ] = sw1.y;
				skinWeightArray[ offset_skin + 2 ] = sw1.z;
				skinWeightArray[ offset_skin + 3 ] = sw1.w;
				skinWeightArray[ offset_skin + 4 ] = sw2.x;
				skinWeightArray[ offset_skin + 5 ] = sw2.y;
				skinWeightArray[ offset_skin + 6 ] = sw2.z;
				skinWeightArray[ offset_skin + 7 ] = sw2.w;
				skinWeightArray[ offset_skin + 8 ]  = sw3.x;
				skinWeightArray[ offset_skin + 9 ]  = sw3.y;
				skinWeightArray[ offset_skin + 10 ] = sw3.z;
				skinWeightArray[ offset_skin + 11 ] = sw3.w;
				skinWeightArray[ offset_skin + 12 ] = sw4.x;
				skinWeightArray[ offset_skin + 13 ] = sw4.y;
				skinWeightArray[ offset_skin + 14 ] = sw4.z;
				skinWeightArray[ offset_skin + 15 ] = sw4.w;
								si1 = obj_skinIndices[ face.a ];
				si2 = obj_skinIndices[ face.b ];
				si3 = obj_skinIndices[ face.c ];
				si4 = obj_skinIndices[ face.d ];
				skinIndexArray[ offset_skin ]     = si1.x;
				skinIndexArray[ offset_skin + 1 ] = si1.y;
				skinIndexArray[ offset_skin + 2 ] = si1.z;
				skinIndexArray[ offset_skin + 3 ] = si1.w;
				skinIndexArray[ offset_skin + 4 ] = si2.x;
				skinIndexArray[ offset_skin + 5 ] = si2.y;
				skinIndexArray[ offset_skin + 6 ] = si2.z;
				skinIndexArray[ offset_skin + 7 ] = si2.w;
				skinIndexArray[ offset_skin + 8 ]  = si3.x;
				skinIndexArray[ offset_skin + 9 ]  = si3.y;
				skinIndexArray[ offset_skin + 10 ] = si3.z;
				skinIndexArray[ offset_skin + 11 ] = si3.w;
				skinIndexArray[ offset_skin + 12 ] = si4.x;
				skinIndexArray[ offset_skin + 13 ] = si4.y;
				skinIndexArray[ offset_skin + 14 ] = si4.z;
				skinIndexArray[ offset_skin + 15 ] = si4.w;
				offset_skin += 16;
			}
			if ( offset_skin > 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
			}
		}
		if ( dirtyColors && vertexColorType ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces3[ f ]	];
				vertexColors = face.vertexColors;
				faceColor = face.color;
				if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) {
					c1 = vertexColors[ 0 ];
					c2 = vertexColors[ 1 ];
					c3 = vertexColors[ 2 ];
				} else {
					c1 = faceColor;
					c2 = faceColor;
					c3 = faceColor;
				}
				colorArray[ offset_color ]     = c1.r;
				colorArray[ offset_color + 1 ] = c1.g;
				colorArray[ offset_color + 2 ] = c1.b;
				colorArray[ offset_color + 3 ] = c2.r;
				colorArray[ offset_color + 4 ] = c2.g;
				colorArray[ offset_color + 5 ] = c2.b;
				colorArray[ offset_color + 6 ] = c3.r;
				colorArray[ offset_color + 7 ] = c3.g;
				colorArray[ offset_color + 8 ] = c3.b;
				offset_color += 9;
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces4[ f ] ];
				vertexColors = face.vertexColors;
				faceColor = face.color;
				if ( vertexColors.length === 4 && vertexColorType === THREE.VertexColors ) {
					c1 = vertexColors[ 0 ];
					c2 = vertexColors[ 1 ];
					c3 = vertexColors[ 2 ];
					c4 = vertexColors[ 3 ];
				} else {
					c1 = faceColor;
					c2 = faceColor;
					c3 = faceColor;
					c4 = faceColor;
				}
				colorArray[ offset_color ]     = c1.r;
				colorArray[ offset_color + 1 ] = c1.g;
				colorArray[ offset_color + 2 ] = c1.b;
				colorArray[ offset_color + 3 ] = c2.r;
				colorArray[ offset_color + 4 ] = c2.g;
				colorArray[ offset_color + 5 ] = c2.b;
				colorArray[ offset_color + 6 ] = c3.r;
				colorArray[ offset_color + 7 ] = c3.g;
				colorArray[ offset_color + 8 ] = c3.b;
				colorArray[ offset_color + 9 ]  = c4.r;
				colorArray[ offset_color + 10 ] = c4.g;
				colorArray[ offset_color + 11 ] = c4.b;
				offset_color += 12;
			}
			if ( offset_color > 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
			}
		}
		if ( dirtyTangents && geometry.hasTangents ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces3[ f ]	];
				vertexTangents = face.vertexTangents;
				t1 = vertexTangents[ 0 ];
				t2 = vertexTangents[ 1 ];
				t3 = vertexTangents[ 2 ];
				tangentArray[ offset_tangent ]     = t1.x;
				tangentArray[ offset_tangent + 1 ] = t1.y;
				tangentArray[ offset_tangent + 2 ] = t1.z;
				tangentArray[ offset_tangent + 3 ] = t1.w;
				tangentArray[ offset_tangent + 4 ] = t2.x;
				tangentArray[ offset_tangent + 5 ] = t2.y;
				tangentArray[ offset_tangent + 6 ] = t2.z;
				tangentArray[ offset_tangent + 7 ] = t2.w;
				tangentArray[ offset_tangent + 8 ]  = t3.x;
				tangentArray[ offset_tangent + 9 ]  = t3.y;
				tangentArray[ offset_tangent + 10 ] = t3.z;
				tangentArray[ offset_tangent + 11 ] = t3.w;
				offset_tangent += 12;
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces4[ f ] ];
				vertexTangents = face.vertexTangents;
				t1 = vertexTangents[ 0 ];
				t2 = vertexTangents[ 1 ];
				t3 = vertexTangents[ 2 ];
				t4 = vertexTangents[ 3 ];
				tangentArray[ offset_tangent ]     = t1.x;
				tangentArray[ offset_tangent + 1 ] = t1.y;
				tangentArray[ offset_tangent + 2 ] = t1.z;
				tangentArray[ offset_tangent + 3 ] = t1.w;
				tangentArray[ offset_tangent + 4 ] = t2.x;
				tangentArray[ offset_tangent + 5 ] = t2.y;
				tangentArray[ offset_tangent + 6 ] = t2.z;
				tangentArray[ offset_tangent + 7 ] = t2.w;
				tangentArray[ offset_tangent + 8 ]  = t3.x;
				tangentArray[ offset_tangent + 9 ]  = t3.y;
				tangentArray[ offset_tangent + 10 ] = t3.z;
				tangentArray[ offset_tangent + 11 ] = t3.w;
				tangentArray[ offset_tangent + 12 ] = t4.x;
				tangentArray[ offset_tangent + 13 ] = t4.y;
				tangentArray[ offset_tangent + 14 ] = t4.z;
				tangentArray[ offset_tangent + 15 ] = t4.w;
				offset_tangent += 16;
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
		}
		if ( dirtyNormals && normalType ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces3[ f ]	];
				vertexNormals = face.vertexNormals;
				faceNormal = face.normal;
				if ( vertexNormals.length === 3 && needsSmoothNormals ) {
					for ( i = 0; i < 3; i ++ ) {
						vn = vertexNormals[ i ];
						normalArray[ offset_normal ]     = vn.x;
						normalArray[ offset_normal + 1 ] = vn.y;
						normalArray[ offset_normal + 2 ] = vn.z;
						offset_normal += 3;
					}
				} else {
					for ( i = 0; i < 3; i ++ ) {
						normalArray[ offset_normal ]     = faceNormal.x;
						normalArray[ offset_normal + 1 ] = faceNormal.y;
						normalArray[ offset_normal + 2 ] = faceNormal.z;
						offset_normal += 3;
					}
				}
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				face = obj_faces[ chunk_faces4[ f ] ];
				vertexNormals = face.vertexNormals;
				faceNormal = face.normal;
				if ( vertexNormals.length === 4 && needsSmoothNormals ) {
					for ( i = 0; i < 4; i ++ ) {
						vn = vertexNormals[ i ];
						normalArray[ offset_normal ]     = vn.x;
						normalArray[ offset_normal + 1 ] = vn.y;
						normalArray[ offset_normal + 2 ] = vn.z;
						offset_normal += 3;
					}
				} else {
					for ( i = 0; i < 4; i ++ ) {
						normalArray[ offset_normal ]     = faceNormal.x;
						normalArray[ offset_normal + 1 ] = faceNormal.y;
						normalArray[ offset_normal + 2 ] = faceNormal.z;
						offset_normal += 3;
					}
				}
			}
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
		}
		if ( dirtyUvs && obj_uvs && uvType ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				fi = chunk_faces3[ f ];
				uv = obj_uvs[ fi ];
				if ( uv === undefined ) continue;
				for ( i = 0; i < 3; i ++ ) {
					uvi = uv[ i ];
					uvArray[ offset_uv ]     = uvi.x;
					uvArray[ offset_uv + 1 ] = uvi.y;
					offset_uv += 2;
				}
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				fi = chunk_faces4[ f ];
				uv = obj_uvs[ fi ];
				if ( uv === undefined ) continue;
				for ( i = 0; i < 4; i ++ ) {
					uvi = uv[ i ];
					uvArray[ offset_uv ]     = uvi.x;
					uvArray[ offset_uv + 1 ] = uvi.y;
					offset_uv += 2;
				}
			}
			if ( offset_uv > 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
			}
		}
		if ( dirtyUvs && obj_uvs2 && uvType ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				fi = chunk_faces3[ f ];
				uv2 = obj_uvs2[ fi ];
				if ( uv2 === undefined ) continue;
				for ( i = 0; i < 3; i ++ ) {
					uv2i = uv2[ i ];
					uv2Array[ offset_uv2 ]     = uv2i.x;
					uv2Array[ offset_uv2 + 1 ] = uv2i.y;
					offset_uv2 += 2;
				}
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				fi = chunk_faces4[ f ];
				uv2 = obj_uvs2[ fi ];
				if ( uv2 === undefined ) continue;
				for ( i = 0; i < 4; i ++ ) {
					uv2i = uv2[ i ];
					uv2Array[ offset_uv2 ]     = uv2i.x;
					uv2Array[ offset_uv2 + 1 ] = uv2i.y;
					offset_uv2 += 2;
				}
			}
			if ( offset_uv2 > 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
			}
		}
		if ( dirtyElements ) {
			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
				faceArray[ offset_face ] 	 = vertexIndex;
				faceArray[ offset_face + 1 ] = vertexIndex + 1;
				faceArray[ offset_face + 2 ] = vertexIndex + 2;
				offset_face += 3;
				lineArray[ offset_line ]     = vertexIndex;
				lineArray[ offset_line + 1 ] = vertexIndex + 1;
				lineArray[ offset_line + 2 ] = vertexIndex;
				lineArray[ offset_line + 3 ] = vertexIndex + 2;
				lineArray[ offset_line + 4 ] = vertexIndex + 1;
				lineArray[ offset_line + 5 ] = vertexIndex + 2;
				offset_line += 6;
				vertexIndex += 3;
			}
			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
				faceArray[ offset_face ]     = vertexIndex;
				faceArray[ offset_face + 1 ] = vertexIndex + 1;
				faceArray[ offset_face + 2 ] = vertexIndex + 3;
				faceArray[ offset_face + 3 ] = vertexIndex + 1;
				faceArray[ offset_face + 4 ] = vertexIndex + 2;
				faceArray[ offset_face + 5 ] = vertexIndex + 3;
				offset_face += 6;
				lineArray[ offset_line ]     = vertexIndex;
				lineArray[ offset_line + 1 ] = vertexIndex + 1;
				lineArray[ offset_line + 2 ] = vertexIndex;
				lineArray[ offset_line + 3 ] = vertexIndex + 3;
				lineArray[ offset_line + 4 ] = vertexIndex + 1;
				lineArray[ offset_line + 5 ] = vertexIndex + 2;
				lineArray[ offset_line + 6 ] = vertexIndex + 2;
				lineArray[ offset_line + 7 ] = vertexIndex + 3;
				offset_line += 8;
				vertexIndex += 4;
			}
			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
			_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
			_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
		}
		if ( customAttributes ) {
			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
				customAttribute = customAttributes[ i ];
				if ( ! customAttribute.__original.needsUpdate ) continue;
				offset_custom = 0;
				offset_customSrc = 0;
				if ( customAttribute.size === 1 ) {
					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces3[ f ]	];
							customAttribute.array[ offset_custom ] 	   = customAttribute.value[ face.a ];
							customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
							customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
							offset_custom += 3;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces4[ f ] ];
							customAttribute.array[ offset_custom ] 	   = customAttribute.value[ face.a ];
							customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
							customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
							customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ];
							offset_custom += 4;
						}
					} else if ( customAttribute.boundTo === "faces" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces3[ f ] ];
							customAttribute.array[ offset_custom ] 	   = value;
							customAttribute.array[ offset_custom + 1 ] = value;
							customAttribute.array[ offset_custom + 2 ] = value;
							offset_custom += 3;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces4[ f ] ];
							customAttribute.array[ offset_custom ] 	   = value;
							customAttribute.array[ offset_custom + 1 ] = value;
							customAttribute.array[ offset_custom + 2 ] = value;
							customAttribute.array[ offset_custom + 3 ] = value;
							offset_custom += 4;
						}
					}
				} else if ( customAttribute.size === 2 ) {
					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces3[ f ]	];
							v1 = customAttribute.value[ face.a ];
							v2 = customAttribute.value[ face.b ];
							v3 = customAttribute.value[ face.c ];
							customAttribute.array[ offset_custom ] 	   = v1.x;
							customAttribute.array[ offset_custom + 1 ] = v1.y;
							customAttribute.array[ offset_custom + 2 ] = v2.x;
							customAttribute.array[ offset_custom + 3 ] = v2.y;
							customAttribute.array[ offset_custom + 4 ] = v3.x;
							customAttribute.array[ offset_custom + 5 ] = v3.y;
							offset_custom += 6;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces4[ f ] ];
							v1 = customAttribute.value[ face.a ];
							v2 = customAttribute.value[ face.b ];
							v3 = customAttribute.value[ face.c ];
							v4 = customAttribute.value[ face.d ];
							customAttribute.array[ offset_custom ] 	   = v1.x;
							customAttribute.array[ offset_custom + 1 ] = v1.y;
							customAttribute.array[ offset_custom + 2 ] = v2.x;
							customAttribute.array[ offset_custom + 3 ] = v2.y;
							customAttribute.array[ offset_custom + 4 ] = v3.x;
							customAttribute.array[ offset_custom + 5 ] = v3.y;
							customAttribute.array[ offset_custom + 6 ] = v4.x;
							customAttribute.array[ offset_custom + 7 ] = v4.y;
							offset_custom += 8;
						}
					} else if ( customAttribute.boundTo === "faces" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces3[ f ] ];
							v1 = value;
							v2 = value;
							v3 = value;
							customAttribute.array[ offset_custom ] 	   = v1.x;
							customAttribute.array[ offset_custom + 1 ] = v1.y;
							customAttribute.array[ offset_custom + 2 ] = v2.x;
							customAttribute.array[ offset_custom + 3 ] = v2.y;
							customAttribute.array[ offset_custom + 4 ] = v3.x;
							customAttribute.array[ offset_custom + 5 ] = v3.y;
							offset_custom += 6;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces4[ f ] ];
							v1 = value;
							v2 = value;
							v3 = value;
							v4 = value;
							customAttribute.array[ offset_custom ] 	   = v1.x;
							customAttribute.array[ offset_custom + 1 ] = v1.y;
							customAttribute.array[ offset_custom + 2 ] = v2.x;
							customAttribute.array[ offset_custom + 3 ] = v2.y;
							customAttribute.array[ offset_custom + 4 ] = v3.x;
							customAttribute.array[ offset_custom + 5 ] = v3.y;
							customAttribute.array[ offset_custom + 6 ] = v4.x;
							customAttribute.array[ offset_custom + 7 ] = v4.y;
							offset_custom += 8;
						}
					}
				} else if ( customAttribute.size === 3 ) {
					var pp;
					if ( customAttribute.type === "c" ) {
						pp = [ "r", "g", "b" ];
					} else {
						pp = [ "x", "y", "z" ];
					}
					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces3[ f ]	];
							v1 = customAttribute.value[ face.a ];
							v2 = customAttribute.value[ face.b ];
							v3 = customAttribute.value[ face.c ];
							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
							offset_custom += 9;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces4[ f ] ];
							v1 = customAttribute.value[ face.a ];
							v2 = customAttribute.value[ face.b ];
							v3 = customAttribute.value[ face.c ];
							v4 = customAttribute.value[ face.d ];
							customAttribute.array[ offset_custom  ] 	= v1[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
							offset_custom += 12;
						}
					} else if ( customAttribute.boundTo === "faces" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces3[ f ] ];
							v1 = value;
							v2 = value;
							v3 = value;
							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
							offset_custom += 9;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces4[ f ] ];
							v1 = value;
							v2 = value;
							v3 = value;
							v4 = value;
							customAttribute.array[ offset_custom  ] 	= v1[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
							offset_custom += 12;
						}
					} else if ( customAttribute.boundTo === "faceVertices" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces3[ f ] ];
							v1 = value[ 0 ];
							v2 = value[ 1 ];
							v3 = value[ 2 ];
							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
							offset_custom += 9;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces4[ f ] ];
							v1 = value[ 0 ];
							v2 = value[ 1 ];
							v3 = value[ 2 ];
							v4 = value[ 3 ];
							customAttribute.array[ offset_custom  ] 	= v1[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];
							customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
							customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
							customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
							offset_custom += 12;
						}
					}
				} else if ( customAttribute.size === 4 ) {
					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces3[ f ]	];
							v1 = customAttribute.value[ face.a ];
							v2 = customAttribute.value[ face.b ];
							v3 = customAttribute.value[ face.c ];
							customAttribute.array[ offset_custom  ] 	= v1.x;
							customAttribute.array[ offset_custom + 1  ] = v1.y;
							customAttribute.array[ offset_custom + 2  ] = v1.z;
							customAttribute.array[ offset_custom + 3  ] = v1.w;
							customAttribute.array[ offset_custom + 4  ] = v2.x;
							customAttribute.array[ offset_custom + 5  ] = v2.y;
							customAttribute.array[ offset_custom + 6  ] = v2.z;
							customAttribute.array[ offset_custom + 7  ] = v2.w;
							customAttribute.array[ offset_custom + 8  ] = v3.x;
							customAttribute.array[ offset_custom + 9  ] = v3.y;
							customAttribute.array[ offset_custom + 10 ] = v3.z;
							customAttribute.array[ offset_custom + 11 ] = v3.w;
							offset_custom += 12;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							face = obj_faces[ chunk_faces4[ f ] ];
							v1 = customAttribute.value[ face.a ];
							v2 = customAttribute.value[ face.b ];
							v3 = customAttribute.value[ face.c ];
							v4 = customAttribute.value[ face.d ];
							customAttribute.array[ offset_custom  ] 	= v1.x;
							customAttribute.array[ offset_custom + 1  ] = v1.y;
							customAttribute.array[ offset_custom + 2  ] = v1.z;
							customAttribute.array[ offset_custom + 3  ] = v1.w;
							customAttribute.array[ offset_custom + 4  ] = v2.x;
							customAttribute.array[ offset_custom + 5  ] = v2.y;
							customAttribute.array[ offset_custom + 6  ] = v2.z;
							customAttribute.array[ offset_custom + 7  ] = v2.w;
							customAttribute.array[ offset_custom + 8  ] = v3.x;
							customAttribute.array[ offset_custom + 9  ] = v3.y;
							customAttribute.array[ offset_custom + 10 ] = v3.z;
							customAttribute.array[ offset_custom + 11 ] = v3.w;
							customAttribute.array[ offset_custom + 12 ] = v4.x;
							customAttribute.array[ offset_custom + 13 ] = v4.y;
							customAttribute.array[ offset_custom + 14 ] = v4.z;
							customAttribute.array[ offset_custom + 15 ] = v4.w;
							offset_custom += 16;
						}
					} else if ( customAttribute.boundTo === "faces" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces3[ f ] ];
							v1 = value;
							v2 = value;
							v3 = value;
							customAttribute.array[ offset_custom  ] 	= v1.x;
							customAttribute.array[ offset_custom + 1  ] = v1.y;
							customAttribute.array[ offset_custom + 2  ] = v1.z;
							customAttribute.array[ offset_custom + 3  ] = v1.w;
							customAttribute.array[ offset_custom + 4  ] = v2.x;
							customAttribute.array[ offset_custom + 5  ] = v2.y;
							customAttribute.array[ offset_custom + 6  ] = v2.z;
							customAttribute.array[ offset_custom + 7  ] = v2.w;
							customAttribute.array[ offset_custom + 8  ] = v3.x;
							customAttribute.array[ offset_custom + 9  ] = v3.y;
							customAttribute.array[ offset_custom + 10 ] = v3.z;
							customAttribute.array[ offset_custom + 11 ] = v3.w;
							offset_custom += 12;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces4[ f ] ];
							v1 = value;
							v2 = value;
							v3 = value;
							v4 = value;
							customAttribute.array[ offset_custom  ] 	= v1.x;
							customAttribute.array[ offset_custom + 1  ] = v1.y;
							customAttribute.array[ offset_custom + 2  ] = v1.z;
							customAttribute.array[ offset_custom + 3  ] = v1.w;
							customAttribute.array[ offset_custom + 4  ] = v2.x;
							customAttribute.array[ offset_custom + 5  ] = v2.y;
							customAttribute.array[ offset_custom + 6  ] = v2.z;
							customAttribute.array[ offset_custom + 7  ] = v2.w;
							customAttribute.array[ offset_custom + 8  ] = v3.x;
							customAttribute.array[ offset_custom + 9  ] = v3.y;
							customAttribute.array[ offset_custom + 10 ] = v3.z;
							customAttribute.array[ offset_custom + 11 ] = v3.w;
							customAttribute.array[ offset_custom + 12 ] = v4.x;
							customAttribute.array[ offset_custom + 13 ] = v4.y;
							customAttribute.array[ offset_custom + 14 ] = v4.z;
							customAttribute.array[ offset_custom + 15 ] = v4.w;
							offset_custom += 16;
						}
					} else if ( customAttribute.boundTo === "faceVertices" ) {
						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces3[ f ] ];
							v1 = value[ 0 ];
							v2 = value[ 1 ];
							v3 = value[ 2 ];
							customAttribute.array[ offset_custom  ] 	= v1.x;
							customAttribute.array[ offset_custom + 1  ] = v1.y;
							customAttribute.array[ offset_custom + 2  ] = v1.z;
							customAttribute.array[ offset_custom + 3  ] = v1.w;
							customAttribute.array[ offset_custom + 4  ] = v2.x;
							customAttribute.array[ offset_custom + 5  ] = v2.y;
							customAttribute.array[ offset_custom + 6  ] = v2.z;
							customAttribute.array[ offset_custom + 7  ] = v2.w;
							customAttribute.array[ offset_custom + 8  ] = v3.x;
							customAttribute.array[ offset_custom + 9  ] = v3.y;
							customAttribute.array[ offset_custom + 10 ] = v3.z;
							customAttribute.array[ offset_custom + 11 ] = v3.w;
							offset_custom += 12;
						}
						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
							value = customAttribute.value[ chunk_faces4[ f ] ];
							v1 = value[ 0 ];
							v2 = value[ 1 ];
							v3 = value[ 2 ];
							v4 = value[ 3 ];
							customAttribute.array[ offset_custom  ] 	= v1.x;
							customAttribute.array[ offset_custom + 1  ] = v1.y;
							customAttribute.array[ offset_custom + 2  ] = v1.z;
							customAttribute.array[ offset_custom + 3  ] = v1.w;
							customAttribute.array[ offset_custom + 4  ] = v2.x;
							customAttribute.array[ offset_custom + 5  ] = v2.y;
							customAttribute.array[ offset_custom + 6  ] = v2.z;
							customAttribute.array[ offset_custom + 7  ] = v2.w;
							customAttribute.array[ offset_custom + 8  ] = v3.x;
							customAttribute.array[ offset_custom + 9  ] = v3.y;
							customAttribute.array[ offset_custom + 10 ] = v3.z;
							customAttribute.array[ offset_custom + 11 ] = v3.w;
							customAttribute.array[ offset_custom + 12 ] = v4.x;
							customAttribute.array[ offset_custom + 13 ] = v4.y;
							customAttribute.array[ offset_custom + 14 ] = v4.z;
							customAttribute.array[ offset_custom + 15 ] = v4.w;
							offset_custom += 16;
						}
					}
				}
				_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
			}
		}
		if ( dispose ) {
			delete geometryGroup.__inittedArrays;
			delete geometryGroup.__colorArray;
			delete geometryGroup.__normalArray;
			delete geometryGroup.__tangentArray;
			delete geometryGroup.__uvArray;
			delete geometryGroup.__uv2Array;
			delete geometryGroup.__faceArray;
			delete geometryGroup.__vertexArray;
			delete geometryGroup.__lineArray;
			delete geometryGroup.__skinIndexArray;
			delete geometryGroup.__skinWeightArray;
		}
	};
	function setDirectBuffers ( geometry, hint, dispose ) {
		var attributes = geometry.attributes;
		var attributeName, attributeItem;
		for ( attributeName in attributes ) {
			attributeItem = attributes[ attributeName ];
			if ( attributeItem.needsUpdate ) {
				if ( attributeName === 'index' ) {
					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer );
					_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint );
				} else {
					_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
					_gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint );
				}
				attributeItem.needsUpdate = false;
			}
			if ( dispose && ! attributeItem.dynamic ) {
				attributeItem.array = null;
			}
		}
	};
		this.renderBufferImmediate = function ( object, program, material ) {
		if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
		if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
		if ( object.hasPositions ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
			_gl.enableVertexAttribArray( program.attributes.position );
			_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
		}
		if ( object.hasNormals ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
			if ( material.shading === THREE.FlatShading ) {
				var nx, ny, nz,
					nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
					normalArray,
					i, il = object.count * 3;
				for( i = 0; i < il; i += 9 ) {
					normalArray = object.normalArray;
					nax  = normalArray[ i ];
					nay  = normalArray[ i + 1 ];
					naz  = normalArray[ i + 2 ];
					nbx  = normalArray[ i + 3 ];
					nby  = normalArray[ i + 4 ];
					nbz  = normalArray[ i + 5 ];
					ncx  = normalArray[ i + 6 ];
					ncy  = normalArray[ i + 7 ];
					ncz  = normalArray[ i + 8 ];
					nx = ( nax + nbx + ncx ) / 3;
					ny = ( nay + nby + ncy ) / 3;
					nz = ( naz + nbz + ncz ) / 3;
					normalArray[ i ] 	 = nx;
					normalArray[ i + 1 ] = ny;
					normalArray[ i + 2 ] = nz;
					normalArray[ i + 3 ] = nx;
					normalArray[ i + 4 ] = ny;
					normalArray[ i + 5 ] = nz;
					normalArray[ i + 6 ] = nx;
					normalArray[ i + 7 ] = ny;
					normalArray[ i + 8 ] = nz;
				}
			}
			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
			_gl.enableVertexAttribArray( program.attributes.normal );
			_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
		}
		if ( object.hasUvs && material.map ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
			_gl.enableVertexAttribArray( program.attributes.uv );
			_gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
		}
		if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
			_gl.enableVertexAttribArray( program.attributes.color );
			_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
		}
		_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
		object.count = 0;
	};
	this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
		if ( material.visible === false ) return;
		var linewidth, a, attribute;
		var attributeItem, attributeName, attributePointer, attributeSize;
		var program = setProgram( camera, lights, fog, material, object );
		var programAttributes = program.attributes;
		var geometryAttributes = geometry.attributes;
		var updateBuffers = false,
			wireframeBit = material.wireframe ? 1 : 0,
			geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
		if ( geometryHash !== _currentGeometryGroupHash ) {
			_currentGeometryGroupHash = geometryHash;
			updateBuffers = true;
		}
		if ( updateBuffers ) {
			disableAttributes();
		}
				if ( object instanceof THREE.Mesh ) {
			var index = geometryAttributes[ "index" ];
						if ( index ) {
				var offsets = geometry.offsets;
																if ( offsets.length > 1 ) updateBuffers = true;
				for ( var i = 0, il = offsets.length; i < il; i ++ ) {
					var startIndex = offsets[ i ].index;
					if ( updateBuffers ) {
						for ( attributeName in geometryAttributes ) {
							if ( attributeName === 'index' ) continue;
							attributePointer = programAttributes[ attributeName ];
							attributeItem = geometryAttributes[ attributeName ];
							attributeSize = attributeItem.itemSize;
							if ( attributePointer >= 0 ) {
								_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
								enableAttribute( attributePointer );
								_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); 							}
						}
												_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
					}
										_gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); 					_this.info.render.calls ++;
					_this.info.render.vertices += offsets[ i ].count; 					_this.info.render.faces += offsets[ i ].count / 3;
				}
						} else {
				if ( updateBuffers ) {
					for ( attributeName in geometryAttributes ) {
						if ( attributeName === 'index') continue;
						attributePointer = programAttributes[ attributeName ];
						attributeItem = geometryAttributes[ attributeName ];
						attributeSize = attributeItem.itemSize;
						if ( attributePointer >= 0 ) {
							_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
							enableAttribute( attributePointer );
							_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
						}
					}
				}
				var position = geometry.attributes[ "position" ];
								_gl.drawArrays( _gl.TRIANGLES, 0, position.numItems / 3 );
				_this.info.render.calls ++;
				_this.info.render.vertices += position.numItems / 3;
				_this.info.render.faces += position.numItems / 3 / 3;
			}
				} else if ( object instanceof THREE.ParticleSystem ) {
			if ( updateBuffers ) {
				for ( attributeName in geometryAttributes ) {
					attributePointer = programAttributes[ attributeName ];
					attributeItem = geometryAttributes[ attributeName ];
					attributeSize = attributeItem.itemSize;
					if ( attributePointer >= 0 ) {
						_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
						enableAttribute( attributePointer );
						_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
					}
				}
				var position = geometryAttributes[ "position" ];
								_gl.drawArrays( _gl.POINTS, 0, position.numItems / 3 );
				_this.info.render.calls ++;
				_this.info.render.points += position.numItems / 3;
			}
		} else if ( object instanceof THREE.Line ) {
			if ( updateBuffers ) {
				for ( attributeName in geometryAttributes ) {
					attributePointer = programAttributes[ attributeName ];
					attributeItem = geometryAttributes[ attributeName ];
					attributeSize = attributeItem.itemSize;
					if ( attributePointer >= 0 ) {
						_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
						enableAttribute( attributePointer );
						_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
					}
				}
								var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
				setLineWidth( material.linewidth );
				var position = geometryAttributes[ "position" ];
				_gl.drawArrays( primitives, 0, position.numItems / 3 );
				_this.info.render.calls ++;
				_this.info.render.points += position.numItems;
			}
    	}
	};
	this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
		if ( material.visible === false ) return;
		var linewidth, a, attribute, i, il;
		var program = setProgram( camera, lights, fog, material, object );
		var attributes = program.attributes;
		var updateBuffers = false,
			wireframeBit = material.wireframe ? 1 : 0,
			geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
		if ( geometryGroupHash !== _currentGeometryGroupHash ) {
			_currentGeometryGroupHash = geometryGroupHash;
			updateBuffers = true;
		}
		if ( updateBuffers ) {
			disableAttributes();
		}
				if ( !material.morphTargets && attributes.position >= 0 ) {
			if ( updateBuffers ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
				enableAttribute( attributes.position );
				_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
			}
		} else {
			if ( object.morphTargetBase ) {
				setupMorphTargets( material, geometryGroup, object );
			}
		}
		if ( updateBuffers ) {
									if ( geometryGroup.__webglCustomAttributesList ) {
				for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
					attribute = geometryGroup.__webglCustomAttributesList[ i ];
					if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
						_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
						enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );
						_gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );
					}
				}
			}
						if ( attributes.color >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
				enableAttribute( attributes.color );
				_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
			}
						if ( attributes.normal >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
				enableAttribute( attributes.normal );
				_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
			}
						if ( attributes.tangent >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
				enableAttribute( attributes.tangent );
				_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
			}
						if ( attributes.uv >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
				enableAttribute( attributes.uv );
				_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
			}
			if ( attributes.uv2 >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
				enableAttribute( attributes.uv2 );
				_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
			}
			if ( material.skinning &&
				 attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
				enableAttribute( attributes.skinIndex );
				_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
				enableAttribute( attributes.skinWeight );
				_gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
			}
						if ( attributes.lineDistance >= 0 ) {
				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer );
				enableAttribute( attributes.lineDistance );
				_gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );
			}
		}
				if ( object instanceof THREE.Mesh ) {
						if ( material.wireframe ) {
				setLineWidth( material.wireframeLinewidth );
				if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
				_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 );
						} else {
				if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
				_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
			}
			_this.info.render.calls ++;
			_this.info.render.vertices += geometryGroup.__webglFaceCount;
			_this.info.render.faces += geometryGroup.__webglFaceCount / 3;
				} else if ( object instanceof THREE.Line ) {
			var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
			setLineWidth( material.linewidth );
			_gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount );
			_this.info.render.calls ++;
				} else if ( object instanceof THREE.ParticleSystem ) {
			_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
			_this.info.render.calls ++;
			_this.info.render.points += geometryGroup.__webglParticleCount;
				} else if ( object instanceof THREE.Ribbon ) {
			_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webglVertexCount );
			_this.info.render.calls ++;
		}
	};
	function enableAttribute( attribute ) {
		if ( ! _enabledAttributes[ attribute ] ) {
			_gl.enableVertexAttribArray( attribute );
			_enabledAttributes[ attribute ] = true;
		}
	};
	function disableAttributes() {
		for ( var attribute in _enabledAttributes ) {
			if ( _enabledAttributes[ attribute ] ) {
				_gl.disableVertexAttribArray( attribute );
				_enabledAttributes[ attribute ] = false;
			}
		}
	};
	function setupMorphTargets ( material, geometryGroup, object ) {
				var attributes = material.program.attributes;
		if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
			enableAttribute( attributes.position );
			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
		} else if ( attributes.position >= 0 ) {
			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
			enableAttribute( attributes.position );
			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
		}
		if ( object.morphTargetForcedOrder.length ) {
						var m = 0;
			var order = object.morphTargetForcedOrder;
			var influences = object.morphTargetInfluences;
			while ( m < material.numSupportedMorphTargets && m < order.length ) {
				if ( attributes[ "morphTarget" + m ] >= 0 ) {
					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
					enableAttribute( attributes[ "morphTarget" + m ] );
					_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
				}
				if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );
					enableAttribute( attributes[ "morphNormal" + m ] );
					_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
				}
				object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
				m ++;
			}
		} else {
						var influence, activeInfluenceIndices = [];
			var influences = object.morphTargetInfluences;
			var i, il = influences.length;
			for ( i = 0; i < il; i ++ ) {
				influence = influences[ i ];
				if ( influence > 0 ) {
					activeInfluenceIndices.push( [ influence, i ] );
				}
			}
			if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {
				activeInfluenceIndices.sort( numericalSort );
				activeInfluenceIndices.length = material.numSupportedMorphTargets;
			} else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {
				activeInfluenceIndices.sort( numericalSort );
			} else if ( activeInfluenceIndices.length === 0 ) {
				activeInfluenceIndices.push( [ 0, 0 ] );
			};
			var influenceIndex, m = 0;
			while ( m < material.numSupportedMorphTargets ) {
				if ( activeInfluenceIndices[ m ] ) {
					influenceIndex = activeInfluenceIndices[ m ][ 1 ];
					if ( attributes[ "morphTarget" + m ] >= 0 ) {
						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );
						enableAttribute( attributes[ "morphTarget" + m ] );
						_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
					}
					if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );
						enableAttribute( attributes[ "morphNormal" + m ] );
						_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
					}
					object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];
				} else {
					/*
					_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
					if ( material.morphNormals ) {
						_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
					}
					*/
					object.__webglMorphTargetInfluences[ m ] = 0;
				}
				m ++;
			}
		}
				if ( material.program.uniforms.morphTargetInfluences !== null ) {
			_gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
		}
	};
		function painterSortStable ( a, b ) {
		if ( a.z !== b.z ) {
			return b.z - a.z;
		} else {
			return a.id - b.id;
		}
	};
	function numericalSort ( a, b ) {
		return b[ 0 ] - a[ 0 ];
	};
		this.render = function ( scene, camera, renderTarget, forceClear ) {
		if ( camera instanceof THREE.Camera === false ) {
			console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
			return;
		}
		var i, il,
		webglObject, object,
		renderList,
		lights = scene.__lights,
		fog = scene.fog;
				_currentMaterialId = -1;
		_lightsNeedUpdate = true;
				if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
				if ( camera.parent === undefined ) camera.updateMatrixWorld();
		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
		_frustum.setFromMatrix( _projScreenMatrix );
				if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );
				renderPlugins( this.renderPluginsPre, scene, camera );
				_this.info.render.calls = 0;
		_this.info.render.vertices = 0;
		_this.info.render.faces = 0;
		_this.info.render.points = 0;
		this.setRenderTarget( renderTarget );
		if ( this.autoClear || forceClear ) {
			this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
		}
				renderList = scene.__webglObjects;
		for ( i = 0, il = renderList.length; i < il; i ++ ) {
			webglObject = renderList[ i ];
			object = webglObject.object;
			webglObject.id = i;
			webglObject.render = false;
			if ( object.visible ) {
				if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
					setupMatrices( object, camera );
					unrollBufferMaterial( webglObject );
					webglObject.render = true;
					if ( this.sortObjects === true ) {
						if ( object.renderDepth !== null ) {
							webglObject.z = object.renderDepth;
						} else {
							_vector3.getPositionFromMatrix( object.matrixWorld );
							_vector3.applyProjection( _projScreenMatrix );
							webglObject.z = _vector3.z;
						}
					}
				}
			}
		}
		if ( this.sortObjects ) {
			renderList.sort( painterSortStable );
		}
				renderList = scene.__webglObjectsImmediate;
		for ( i = 0, il = renderList.length; i < il; i ++ ) {
			webglObject = renderList[ i ];
			object = webglObject.object;
			if ( object.visible ) {
				setupMatrices( object, camera );
				unrollImmediateBufferMaterial( webglObject );
			}
		}
		if ( scene.overrideMaterial ) {
			var material = scene.overrideMaterial;
			this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
			this.setDepthTest( material.depthTest );
			this.setDepthWrite( material.depthWrite );
			setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
			renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material );
			renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material );
		} else {
			var material = null;
						this.setBlending( THREE.NoBlending );
			renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material );
			renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material );
						renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material );
			renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material );
		}
				renderPlugins( this.renderPluginsPost, scene, camera );
				if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
			updateRenderTargetMipmap( renderTarget );
		}
				this.setDepthTest( true );
		this.setDepthWrite( true );
			};
	function renderPlugins( plugins, scene, camera ) {
		if ( ! plugins.length ) return;
		for ( var i = 0, il = plugins.length; i < il; i ++ ) {
						_currentProgram = null;
			_currentCamera = null;
			_oldBlending = -1;
			_oldDepthTest = -1;
			_oldDepthWrite = -1;
			_oldDoubleSided = -1;
			_oldFlipSided = -1;
			_currentGeometryGroupHash = -1;
			_currentMaterialId = -1;
			_lightsNeedUpdate = true;
			plugins[ i ].render( scene, camera, _currentWidth, _currentHeight );
						_currentProgram = null;
			_currentCamera = null;
			_oldBlending = -1;
			_oldDepthTest = -1;
			_oldDepthWrite = -1;
			_oldDoubleSided = -1;
			_oldFlipSided = -1;
			_currentGeometryGroupHash = -1;
			_currentMaterialId = -1;
			_lightsNeedUpdate = true;
		}
	};
	function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
		var webglObject, object, buffer, material, start, end, delta;
		if ( reverse ) {
			start = renderList.length - 1;
			end = -1;
			delta = -1;
		} else {
			start = 0;
			end = renderList.length;
			delta = 1;
		}
		for ( var i = start; i !== end; i += delta ) {
			webglObject = renderList[ i ];
			if ( webglObject.render ) {
				object = webglObject.object;
				buffer = webglObject.buffer;
				if ( overrideMaterial ) {
					material = overrideMaterial;
				} else {
					material = webglObject[ materialType ];
					if ( ! material ) continue;
					if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
					_this.setDepthTest( material.depthTest );
					_this.setDepthWrite( material.depthWrite );
					setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
				}
				_this.setMaterialFaces( material );
				if ( buffer instanceof THREE.BufferGeometry ) {
					_this.renderBufferDirect( camera, lights, fog, material, buffer, object );
				} else {
					_this.renderBuffer( camera, lights, fog, material, buffer, object );
				}
			}
		}
	};
	function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
		var webglObject, object, material, program;
		for ( var i = 0, il = renderList.length; i < il; i ++ ) {
			webglObject = renderList[ i ];
			object = webglObject.object;
			if ( object.visible ) {
				if ( overrideMaterial ) {
					material = overrideMaterial;
				} else {
					material = webglObject[ materialType ];
					if ( ! material ) continue;
					if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
					_this.setDepthTest( material.depthTest );
					_this.setDepthWrite( material.depthWrite );
					setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
				}
				_this.renderImmediateObject( camera, lights, fog, material, object );
			}
		}
	};
	this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
		var program = setProgram( camera, lights, fog, material, object );
		_currentGeometryGroupHash = -1;
		_this.setMaterialFaces( material );
		if ( object.immediateRenderCallback ) {
			object.immediateRenderCallback( program, _gl, _frustum );
		} else {
			object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } );
		}
	};
	function unrollImmediateBufferMaterial ( globject ) {
		var object = globject.object,
			material = object.material;
		if ( material.transparent ) {
			globject.transparent = material;
			globject.opaque = null;
		} else {
			globject.opaque = material;
			globject.transparent = null;
		}
	};
	function unrollBufferMaterial ( globject ) {
		var object = globject.object,
			buffer = globject.buffer,
			material, materialIndex, meshMaterial;
		meshMaterial = object.material;
		if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
			materialIndex = buffer.materialIndex;
			material = meshMaterial.materials[ materialIndex ];
			if ( material.transparent ) {
				globject.transparent = material;
				globject.opaque = null;
			} else {
				globject.opaque = material;
				globject.transparent = null;
			}
		} else {
			material = meshMaterial;
			if ( material ) {
				if ( material.transparent ) {
					globject.transparent = material;
					globject.opaque = null;
				} else {
					globject.opaque = material;
					globject.transparent = null;
				}
			}
		}
	};
		function sortFacesByMaterial ( geometry, material ) {
		var f, fl, face, materialIndex, vertices,
			groupHash, hash_map = {};
		var numMorphTargets = geometry.morphTargets.length;
		var numMorphNormals = geometry.morphNormals.length;
		var usesFaceMaterial = material instanceof THREE.MeshFaceMaterial;
		geometry.geometryGroups = {};
		for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
			face = geometry.faces[ f ];
			materialIndex = usesFaceMaterial ? face.materialIndex : 0;
			if ( hash_map[ materialIndex ] === undefined ) {
				hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 };
			}
			groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
			if ( geometry.geometryGroups[ groupHash ] === undefined ) {
				geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
			}
			vertices = face instanceof THREE.Face3 ? 3 : 4;
			if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) {
				hash_map[ materialIndex ].counter += 1;
				groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
				if ( geometry.geometryGroups[ groupHash ] === undefined ) {
					geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
				}
			}
			if ( face instanceof THREE.Face3 ) {
				geometry.geometryGroups[ groupHash ].faces3.push( f );
			} else {
				geometry.geometryGroups[ groupHash ].faces4.push( f );
			}
			geometry.geometryGroups[ groupHash ].vertices += vertices;
		}
		geometry.geometryGroupsList = [];
		for ( var g in geometry.geometryGroups ) {
			geometry.geometryGroups[ g ].id = _geometryGroupCounter ++;
			geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] );
		}
	};
		this.initWebGLObjects = function ( scene ) {
		if ( !scene.__webglObjects ) {
			scene.__webglObjects = [];
			scene.__webglObjectsImmediate = [];
			scene.__webglSprites = [];
			scene.__webglFlares = [];
		}
		while ( scene.__objectsAdded.length ) {
			addObject( scene.__objectsAdded[ 0 ], scene );
			scene.__objectsAdded.splice( 0, 1 );
		}
		while ( scene.__objectsRemoved.length ) {
			removeObject( scene.__objectsRemoved[ 0 ], scene );
			scene.__objectsRemoved.splice( 0, 1 );
		}
				for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
			var object = scene.__webglObjects[ o ].object;
						if ( object.__webglInit === undefined ) {
				if ( object.__webglActive !== undefined ) {
					removeObject( object, scene );
				}
				addObject( object, scene );
			}
			updateObject( object );
		}
	};
		function addObject( object, scene ) {
		var g, geometry, material, geometryGroup;
		if ( object.__webglInit === undefined ) {
			object.__webglInit = true;
			object._modelViewMatrix = new THREE.Matrix4();
			object._normalMatrix = new THREE.Matrix3();
			if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) {
				object.geometry.__webglInit = true;
				object.geometry.addEventListener( 'dispose', onGeometryDispose );
			}
			geometry = object.geometry;
			if ( geometry === undefined ) {
							} else if ( geometry instanceof THREE.BufferGeometry ) {
				initDirectBuffers( geometry );
			} else if ( object instanceof THREE.Mesh ) {
				material = object.material;
				if ( geometry.geometryGroups === undefined ) {
					sortFacesByMaterial( geometry, material );
				}
								for ( g in geometry.geometryGroups ) {
					geometryGroup = geometry.geometryGroups[ g ];
										if ( ! geometryGroup.__webglVertexBuffer ) {
						createMeshBuffers( geometryGroup );
						initMeshBuffers( geometryGroup, object );
						geometry.verticesNeedUpdate = true;
						geometry.morphTargetsNeedUpdate = true;
						geometry.elementsNeedUpdate = true;
						geometry.uvsNeedUpdate = true;
						geometry.normalsNeedUpdate = true;
						geometry.tangentsNeedUpdate = true;
						geometry.colorsNeedUpdate = true;
					}
				}
			} else if ( object instanceof THREE.Ribbon ) {
				if ( ! geometry.__webglVertexBuffer ) {
					createRibbonBuffers( geometry );
					initRibbonBuffers( geometry, object );
					geometry.verticesNeedUpdate = true;
					geometry.colorsNeedUpdate = true;
					geometry.normalsNeedUpdate = true;
				}
			} else if ( object instanceof THREE.Line ) {
				if ( ! geometry.__webglVertexBuffer ) {
					createLineBuffers( geometry );
					initLineBuffers( geometry, object );
					geometry.verticesNeedUpdate = true;
					geometry.colorsNeedUpdate = true;
					geometry.lineDistancesNeedUpdate = true;
				}
			} else if ( object instanceof THREE.ParticleSystem ) {
				if ( ! geometry.__webglVertexBuffer ) {
					createParticleBuffers( geometry );
					initParticleBuffers( geometry, object );
					geometry.verticesNeedUpdate = true;
					geometry.colorsNeedUpdate = true;
				}
			}
		}
		if ( object.__webglActive === undefined ) {
			if ( object instanceof THREE.Mesh ) {
				geometry = object.geometry;
				if ( geometry instanceof THREE.BufferGeometry ) {
					addBuffer( scene.__webglObjects, geometry, object );
				} else if ( geometry instanceof THREE.Geometry ) {
					for ( g in geometry.geometryGroups ) {
						geometryGroup = geometry.geometryGroups[ g ];
						addBuffer( scene.__webglObjects, geometryGroup, object );
					}
				}
			}
			object.__webglActive = true;
		}
	};
	function addBuffer( objlist, buffer, object ) {
		objlist.push(
			{
				id: null,
				buffer: buffer,
				object: object,
				opaque: null,
				transparent: null,
				z: 0
			}
		);
	};
	function addBufferImmediate( objlist, object ) {
		objlist.push(
			{
				id: null,
				object: object,
				opaque: null,
				transparent: null,
				z: 0
			}
		);
	};
		function updateObject( object ) {
		var geometry = object.geometry,
			geometryGroup, customAttributesDirty, material;
		if ( geometry instanceof THREE.BufferGeometry ) {
			setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic );
		} else if ( object instanceof THREE.Mesh ) {
						for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
				geometryGroup = geometry.geometryGroupsList[ i ];
				material = getBufferMaterial( object, geometryGroup );
				if ( geometry.buffersNeedUpdate ) {
					initMeshBuffers( geometryGroup, object );
				}
				customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
				if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
					 geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
					 geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {
					setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material );
				}
			}
			geometry.verticesNeedUpdate = false;
			geometry.morphTargetsNeedUpdate = false;
			geometry.elementsNeedUpdate = false;
			geometry.uvsNeedUpdate = false;
			geometry.normalsNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			geometry.tangentsNeedUpdate = false;
			geometry.buffersNeedUpdate = false;
			material.attributes && clearCustomAttributes( material );
		} else if ( object instanceof THREE.Ribbon ) {
			material = getBufferMaterial( object, geometry );
			customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.normalsNeedUpdate || customAttributesDirty ) {
				setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW );
			}
			geometry.verticesNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			geometry.normalsNeedUpdate = false;
			material.attributes && clearCustomAttributes( material );
		} else if ( object instanceof THREE.Line ) {
			material = getBufferMaterial( object, geometry );
			customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {
				setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
			}
			geometry.verticesNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			geometry.lineDistancesNeedUpdate = false;
			material.attributes && clearCustomAttributes( material );
		} else if ( object instanceof THREE.ParticleSystem ) {
			material = getBufferMaterial( object, geometry );
			customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) {
				setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
			}
			geometry.verticesNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			material.attributes && clearCustomAttributes( material );
		}
	};
		function areCustomAttributesDirty( material ) {
		for ( var a in material.attributes ) {
			if ( material.attributes[ a ].needsUpdate ) return true;
		}
		return false;
	};
	function clearCustomAttributes( material ) {
		for ( var a in material.attributes ) {
			material.attributes[ a ].needsUpdate = false;
		}
	};
		function removeObject( object, scene ) {
		if ( object instanceof THREE.Mesh  ||
			 object instanceof THREE.ParticleSystem ||
			 object instanceof THREE.Ribbon ||
			 object instanceof THREE.Line ) {
			removeInstances( scene.__webglObjects, object );
		} else if ( object instanceof THREE.Sprite ) {
			removeInstancesDirect( scene.__webglSprites, object );
		} else if ( object instanceof THREE.LensFlare ) {
			removeInstancesDirect( scene.__webglFlares, object );
		} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
			removeInstances( scene.__webglObjectsImmediate, object );
		}
		delete object.__webglActive;
	};
	function removeInstances( objlist, object ) {
		for ( var o = objlist.length - 1; o >= 0; o -- ) {
			if ( objlist[ o ].object === object ) {
				objlist.splice( o, 1 );
			}
		}
	};
	function removeInstancesDirect( objlist, object ) {
		for ( var o = objlist.length - 1; o >= 0; o -- ) {
			if ( objlist[ o ] === object ) {
				objlist.splice( o, 1 );
			}
		}
	};
		this.initMaterial = function ( material, lights, fog, object ) {
		material.addEventListener( 'dispose', onMaterialDispose );
		var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;
		if ( material instanceof THREE.MeshBasicMaterial ) {
			shaderID = 'basic';
		} else if ( material instanceof THREE.MeshLambertMaterial ) {
			shaderID = 'lambert';
		}
		if ( shaderID ) {
			setMaterialShaders( material, THREE.ShaderLib[ shaderID ] );
		}
						maxLightCount = allocateLights( lights );
		maxShadows = allocateShadows( lights );
		maxBones = allocateBones( object );
		parameters = {
			map: !!material.map,
			envMap: !!material.envMap,
			lightMap: !!material.lightMap,
			bumpMap: !!material.bumpMap,
			normalMap: !!material.normalMap,
			specularMap: !!material.specularMap,
			vertexColors: material.vertexColors,
			fog: fog,
			useFog: material.fog,
			fogExp: fog instanceof THREE.FogExp2,
			sizeAttenuation: material.sizeAttenuation,
			skinning: material.skinning,
			maxBones: maxBones,
			useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture,
			boneTextureWidth: object && object.boneTextureWidth,
			boneTextureHeight: object && object.boneTextureHeight,
			morphTargets: material.morphTargets,
			morphNormals: material.morphNormals,
			maxMorphTargets: this.maxMorphTargets,
			maxMorphNormals: this.maxMorphNormals,
			maxDirLights: maxLightCount.directional,
			maxPointLights: maxLightCount.point,
			maxSpotLights: maxLightCount.spot,
			maxHemiLights: maxLightCount.hemi,
			maxShadows: maxShadows,
			shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow,
			shadowMapType: this.shadowMapType,
			shadowMapDebug: this.shadowMapDebug,
			shadowMapCascade: this.shadowMapCascade,
			alphaTest: material.alphaTest,
			metal: material.metal,
			perPixel: material.perPixel,
			wrapAround: material.wrapAround,
			doubleSided: material.side === THREE.DoubleSide,
			flipSided: material.side === THREE.BackSide
		};
		material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters );
		var attributes = material.program.attributes;
		if ( material.morphTargets ) {
			material.numSupportedMorphTargets = 0;
			var id, base = "morphTarget";
			for ( i = 0; i < this.maxMorphTargets; i ++ ) {
				id = base + i;
				if ( attributes[ id ] >= 0 ) {
					material.numSupportedMorphTargets ++;
				}
			}
		}
		if ( material.morphNormals ) {
			material.numSupportedMorphNormals = 0;
			var id, base = "morphNormal";
			for ( i = 0; i < this.maxMorphNormals; i ++ ) {
				id = base + i;
				if ( attributes[ id ] >= 0 ) {
					material.numSupportedMorphNormals ++;
				}
			}
		}
		material.uniformsList = [];
		for ( u in material.uniforms ) {
			material.uniformsList.push( [ material.uniforms[ u ], u ] );
		}
	};
	function setMaterialShaders( material, shaders ) {
		material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
		material.vertexShader = shaders.vertexShader;
		material.fragmentShader = shaders.fragmentShader;
	};
	function setProgram( camera, lights, fog, material, object ) {
		_usedTextureUnits = 0;
		if ( material.needsUpdate ) {
			if ( material.program ) deallocateMaterial( material );
			_this.initMaterial( material, lights, fog, object );
			material.needsUpdate = false;
		}
		if ( material.morphTargets ) {
			if ( ! object.__webglMorphTargetInfluences ) {
				object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
			}
		}
		var refreshMaterial = false;
		var program = material.program,
			p_uniforms = program.uniforms,
			m_uniforms = material.uniforms;
		if ( program !== _currentProgram ) {
			_gl.useProgram( program );
			_currentProgram = program;
			refreshMaterial = true;
		}
		if ( material.id !== _currentMaterialId ) {
			_currentMaterialId = material.id;
			refreshMaterial = true;
		}
		if ( refreshMaterial || camera !== _currentCamera ) {
			_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
			if ( camera !== _currentCamera ) _currentCamera = camera;
		}
								if ( material.skinning ) {
			if ( _supportsBoneTextures && object.useVertexTexture ) {
				if ( p_uniforms.boneTexture !== null ) {
					var textureUnit = getTextureUnit();
					_gl.uniform1i( p_uniforms.boneTexture, textureUnit );
					_this.setTexture( object.boneTexture, textureUnit );
				}
			} else {
				if ( p_uniforms.boneGlobalMatrices !== null ) {
					_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );
				}
			}
		}
		if ( refreshMaterial ) {
						if ( fog && material.fog ) {
				refreshUniformsFog( m_uniforms, fog );
			}
			if ( material instanceof THREE.MeshLambertMaterial ||
				 material.lights ) {
				if ( _lightsNeedUpdate ) {
					setupLights( program, lights );
					_lightsNeedUpdate = false;
				}
				refreshUniformsLights( m_uniforms, _lights );
			}
			if ( material instanceof THREE.MeshBasicMaterial ||
				 material instanceof THREE.MeshLambertMaterial) {
				refreshUniformsCommon( m_uniforms, material );
			}
						if ( material instanceof THREE.MeshLambertMaterial ) {
				refreshUniformsLambert( m_uniforms, material );
			}
			if ( object.receiveShadow && ! material._shadowPass ) {
				refreshUniformsShadow( m_uniforms, lights );
			}
						loadUniformsGeneric( program, material.uniformsList );
									if ( material instanceof THREE.ShaderMaterial ||
				 material.envMap ) {
				if ( p_uniforms.cameraPosition !== null ) {
					_vector3.getPositionFromMatrix( camera.matrixWorld );
					_gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z );
				}
			}
			if (  material instanceof THREE.MeshLambertMaterial ||
				 material instanceof THREE.ShaderMaterial ||
				 material.skinning ) {
				if ( p_uniforms.viewMatrix !== null ) {
					_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );
				}
			}
		}
		loadUniformsMatrices( p_uniforms, object );
		if ( p_uniforms.modelMatrix !== null ) {
			_gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );
		}
		return program;
	};
		function refreshUniformsCommon ( uniforms, material ) {
		uniforms.opacity.value = material.opacity;
		if ( _this.gammaInput ) {
			uniforms.diffuse.value.copyGammaToLinear( material.color );
		} else {
			uniforms.diffuse.value = material.color;
		}
		uniforms.map.value = material.map;
		uniforms.lightMap.value = material.lightMap;
		uniforms.specularMap.value = material.specularMap;
		if ( material.bumpMap ) {
			uniforms.bumpMap.value = material.bumpMap;
			uniforms.bumpScale.value = material.bumpScale;
		}
		if ( material.normalMap ) {
			uniforms.normalMap.value = material.normalMap;
			uniforms.normalScale.value.copy( material.normalScale );
		}
												var uvScaleMap;
		if ( material.map ) {
			uvScaleMap = material.map;
		} else if ( material.specularMap ) {
			uvScaleMap = material.specularMap;
		} else if ( material.normalMap ) {
			uvScaleMap = material.normalMap;
		} else if ( material.bumpMap ) {
			uvScaleMap = material.bumpMap;
		}
		if ( uvScaleMap !== undefined ) {
			var offset = uvScaleMap.offset;
			var repeat = uvScaleMap.repeat;
			uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
		}
		uniforms.envMap.value = material.envMap;
		uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
		if ( _this.gammaInput ) {
						uniforms.reflectivity.value = material.reflectivity;
		} else {
			uniforms.reflectivity.value = material.reflectivity;
		}
		uniforms.refractionRatio.value = material.refractionRatio;
		uniforms.combine.value = material.combine;
		uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
	};
	function refreshUniformsLine ( uniforms, material ) {
		uniforms.diffuse.value = material.color;
		uniforms.opacity.value = material.opacity;
	};
	function refreshUniformsDash ( uniforms, material ) {
		uniforms.dashSize.value = material.dashSize;
		uniforms.totalSize.value = material.dashSize + material.gapSize;
		uniforms.scale.value = material.scale;
	};
	function refreshUniformsParticle ( uniforms, material ) {
		uniforms.psColor.value = material.color;
		uniforms.opacity.value = material.opacity;
		uniforms.size.value = material.size;
		uniforms.scale.value = _canvas.height / 2.0; 		uniforms.map.value = material.map;
	};
	function refreshUniformsFog ( uniforms, fog ) {
		uniforms.fogColor.value = fog.color;
		if ( fog instanceof THREE.Fog ) {
			uniforms.fogNear.value = fog.near;
			uniforms.fogFar.value = fog.far;
		} else if ( fog instanceof THREE.FogExp2 ) {
			uniforms.fogDensity.value = fog.density;
		}
	};
	function refreshUniformsPhong ( uniforms, material ) {
		uniforms.shininess.value = material.shininess;
		if ( _this.gammaInput ) {
			uniforms.ambient.value.copyGammaToLinear( material.ambient );
			uniforms.emissive.value.copyGammaToLinear( material.emissive );
			uniforms.specular.value.copyGammaToLinear( material.specular );
		} else {
			uniforms.ambient.value = material.ambient;
			uniforms.emissive.value = material.emissive;
			uniforms.specular.value = material.specular;
		}
		if ( material.wrapAround ) {
			uniforms.wrapRGB.value.copy( material.wrapRGB );
		}
	};
	function refreshUniformsLambert ( uniforms, material ) {
		if ( _this.gammaInput ) {
			uniforms.ambient.value.copyGammaToLinear( material.ambient );
			uniforms.emissive.value.copyGammaToLinear( material.emissive );
		} else {
			uniforms.ambient.value = material.ambient;
			uniforms.emissive.value = material.emissive;
		}
		if ( material.wrapAround ) {
			uniforms.wrapRGB.value.copy( material.wrapRGB );
		}
	};
	function refreshUniformsLights ( uniforms, lights ) {
		uniforms.ambientLightColor.value = lights.ambient;
		uniforms.directionalLightColor.value = lights.directional.colors;
		uniforms.directionalLightDirection.value = lights.directional.positions;
		uniforms.pointLightColor.value = lights.point.colors;
		uniforms.pointLightPosition.value = lights.point.positions;
		uniforms.pointLightDistance.value = lights.point.distances;
		uniforms.spotLightColor.value = lights.spot.colors;
		uniforms.spotLightPosition.value = lights.spot.positions;
		uniforms.spotLightDistance.value = lights.spot.distances;
		uniforms.spotLightDirection.value = lights.spot.directions;
		uniforms.spotLightAngleCos.value = lights.spot.anglesCos;
		uniforms.spotLightExponent.value = lights.spot.exponents;
		uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
		uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
		uniforms.hemisphereLightDirection.value = lights.hemi.positions;
	};
	function refreshUniformsShadow ( uniforms, lights ) {
		if ( uniforms.shadowMatrix ) {
			var j = 0;
			for ( var i = 0, il = lights.length; i < il; i ++ ) {
				var light = lights[ i ];
				if ( ! light.castShadow ) continue;
				if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {
					uniforms.shadowMap.value[ j ] = light.shadowMap;
					uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
					uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
					uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
					uniforms.shadowBias.value[ j ] = light.shadowBias;
					j ++;
				}
			}
		}
	};
		function loadUniformsMatrices ( uniforms, object ) {
		_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );
		if ( uniforms.normalMatrix ) {
			_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );
		}
	};
	function getTextureUnit() {
		var textureUnit = _usedTextureUnits;
		if ( textureUnit >= _maxTextures ) {
			console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures );
		}
		_usedTextureUnits += 1;
		return textureUnit;
	};
	function loadUniformsGeneric ( program, uniforms ) {
		var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset;
		for ( j = 0, jl = uniforms.length; j < jl; j ++ ) {
			location = program.uniforms[ uniforms[ j ][ 1 ] ];
			if ( !location ) continue;
			uniform = uniforms[ j ][ 0 ];
			type = uniform.type;
			value = uniform.value;
			if ( type === "i" ) { 				_gl.uniform1i( location, value );
			} else if ( type === "f" ) { 				_gl.uniform1f( location, value );
			} else if ( type === "v2" ) { 				_gl.uniform2f( location, value.x, value.y );
			} else if ( type === "v3" ) { 				_gl.uniform3f( location, value.x, value.y, value.z );
			} else if ( type === "v4" ) { 				_gl.uniform4f( location, value.x, value.y, value.z, value.w );
			} else if ( type === "c" ) { 				_gl.uniform3f( location, value.r, value.g, value.b );
			} else if ( type === "iv1" ) { 				_gl.uniform1iv( location, value );
			} else if ( type === "iv" ) { 				_gl.uniform3iv( location, value );
			} else if ( type === "fv1" ) { 				_gl.uniform1fv( location, value );
			} else if ( type === "fv" ) { 				_gl.uniform3fv( location, value );
			} else if ( type === "v2v" ) { 				if ( uniform._array === undefined ) {
					uniform._array = new Float32Array( 2 * value.length );
				}
				for ( i = 0, il = value.length; i < il; i ++ ) {
					offset = i * 2;
					uniform._array[ offset ] 	 = value[ i ].x;
					uniform._array[ offset + 1 ] = value[ i ].y;
				}
				_gl.uniform2fv( location, uniform._array );
			} else if ( type === "v3v" ) { 				if ( uniform._array === undefined ) {
					uniform._array = new Float32Array( 3 * value.length );
				}
				for ( i = 0, il = value.length; i < il; i ++ ) {
					offset = i * 3;
					uniform._array[ offset ] 	 = value[ i ].x;
					uniform._array[ offset + 1 ] = value[ i ].y;
					uniform._array[ offset + 2 ] = value[ i ].z;
				}
				_gl.uniform3fv( location, uniform._array );
			} else if ( type === "v4v" ) { 				if ( uniform._array === undefined ) {
					uniform._array = new Float32Array( 4 * value.length );
				}
				for ( i = 0, il = value.length; i < il; i ++ ) {
					offset = i * 4;
					uniform._array[ offset ] 	 = value[ i ].x;
					uniform._array[ offset + 1 ] = value[ i ].y;
					uniform._array[ offset + 2 ] = value[ i ].z;
					uniform._array[ offset + 3 ] = value[ i ].w;
				}
				_gl.uniform4fv( location, uniform._array );
			} else if ( type === "m4") { 				if ( uniform._array === undefined ) {
					uniform._array = new Float32Array( 16 );
				}
				value.flattenToArray( uniform._array );
				_gl.uniformMatrix4fv( location, false, uniform._array );
			} else if ( type === "m4v" ) { 				if ( uniform._array === undefined ) {
					uniform._array = new Float32Array( 16 * value.length );
				}
				for ( i = 0, il = value.length; i < il; i ++ ) {
					value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
				}
				_gl.uniformMatrix4fv( location, false, uniform._array );
			} else if ( type === "t" ) { 				texture = value;
				textureUnit = getTextureUnit();
				_gl.uniform1i( location, textureUnit );
				if ( !texture ) continue;
				if ( texture.image instanceof Array && texture.image.length === 6 ) {
					setCubeTexture( texture, textureUnit );
				} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
					setCubeTextureDynamic( texture, textureUnit );
				} else {
					_this.setTexture( texture, textureUnit );
				}
			} else if ( type === "tv" ) { 				if ( uniform._array === undefined ) {
					uniform._array = [];
				}
				for( i = 0, il = uniform.value.length; i < il; i ++ ) {
					uniform._array[ i ] = getTextureUnit();
				}
				_gl.uniform1iv( location, uniform._array );
				for( i = 0, il = uniform.value.length; i < il; i ++ ) {
					texture = uniform.value[ i ];
					textureUnit = uniform._array[ i ];
					if ( !texture ) continue;
					_this.setTexture( texture, textureUnit );
				}
			} else {
				console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type );
			}
		}
	};
	function setupMatrices ( object, camera ) {
		object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
		object._normalMatrix.getNormalMatrix( object._modelViewMatrix );
	};
		function setColorGamma( array, offset, color, intensitySq ) {
		array[ offset ]     = color.r * color.r * intensitySq;
		array[ offset + 1 ] = color.g * color.g * intensitySq;
		array[ offset + 2 ] = color.b * color.b * intensitySq;
	};
	function setColorLinear( array, offset, color, intensity ) {
		array[ offset ]     = color.r * intensity;
		array[ offset + 1 ] = color.g * intensity;
		array[ offset + 2 ] = color.b * intensity;
	};
	function setupLights ( program, lights ) {
		var l, ll, light, n,
		r = 0, g = 0, b = 0,
		color, skyColor, groundColor,
		intensity,  intensitySq,
		position,
		distance,
		zlights = _lights,
		dirColors = zlights.directional.colors,
		dirPositions = zlights.directional.positions,
		pointColors = zlights.point.colors,
		pointPositions = zlights.point.positions,
		pointDistances = zlights.point.distances,
		spotColors = zlights.spot.colors,
		spotPositions = zlights.spot.positions,
		spotDistances = zlights.spot.distances,
		spotDirections = zlights.spot.directions,
		spotAnglesCos = zlights.spot.anglesCos,
		spotExponents = zlights.spot.exponents,
		hemiSkyColors = zlights.hemi.skyColors,
		hemiGroundColors = zlights.hemi.groundColors,
		hemiPositions = zlights.hemi.positions,
		dirLength = 0,
		pointLength = 0,
		spotLength = 0,
		hemiLength = 0,
		dirCount = 0,
		pointCount = 0,
		spotCount = 0,
		hemiCount = 0,
		dirOffset = 0,
		pointOffset = 0,
		spotOffset = 0,
		hemiOffset = 0;
		for ( l = 0, ll = lights.length; l < ll; l ++ ) {
			light = lights[ l ];
			if ( light.onlyShadow ) continue;
			color = light.color;
			intensity = light.intensity;
			distance = light.distance;
			if ( light instanceof THREE.AmbientLight ) {
				if ( ! light.visible ) continue;
				if ( _this.gammaInput ) {
					r += color.r * color.r;
					g += color.g * color.g;
					b += color.b * color.b;
				} else {
					r += color.r;
					g += color.g;
					b += color.b;
				}
			} else if ( light instanceof THREE.DirectionalLight ) {
				dirCount += 1;
				if ( ! light.visible ) continue;
				_direction.getPositionFromMatrix( light.matrixWorld );
				_vector3.getPositionFromMatrix( light.target.matrixWorld );
				_direction.sub( _vector3 );
				_direction.normalize();
												if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
				dirOffset = dirLength * 3;
				dirPositions[ dirOffset ]     = _direction.x;
				dirPositions[ dirOffset + 1 ] = _direction.y;
				dirPositions[ dirOffset + 2 ] = _direction.z;
				if ( _this.gammaInput ) {
					setColorGamma( dirColors, dirOffset, color, intensity * intensity );
				} else {
					setColorLinear( dirColors, dirOffset, color, intensity );
				}
				dirLength += 1;
			} else if ( light instanceof THREE.PointLight ) {
				pointCount += 1;
				if ( ! light.visible ) continue;
				pointOffset = pointLength * 3;
				if ( _this.gammaInput ) {
					setColorGamma( pointColors, pointOffset, color, intensity * intensity );
				} else {
					setColorLinear( pointColors, pointOffset, color, intensity );
				}
				_vector3.getPositionFromMatrix( light.matrixWorld );
				pointPositions[ pointOffset ]     = _vector3.x;
				pointPositions[ pointOffset + 1 ] = _vector3.y;
				pointPositions[ pointOffset + 2 ] = _vector3.z;
				pointDistances[ pointLength ] = distance;
				pointLength += 1;
			} else if ( light instanceof THREE.SpotLight ) {
				spotCount += 1;
				if ( ! light.visible ) continue;
				spotOffset = spotLength * 3;
				if ( _this.gammaInput ) {
					setColorGamma( spotColors, spotOffset, color, intensity * intensity );
				} else {
					setColorLinear( spotColors, spotOffset, color, intensity );
				}
				_vector3.getPositionFromMatrix( light.matrixWorld );
				spotPositions[ spotOffset ]     = _vector3.x;
				spotPositions[ spotOffset + 1 ] = _vector3.y;
				spotPositions[ spotOffset + 2 ] = _vector3.z;
				spotDistances[ spotLength ] = distance;
				_direction.copy( _vector3 );
				_vector3.getPositionFromMatrix( light.target.matrixWorld );
				_direction.sub( _vector3 );
				_direction.normalize();
				spotDirections[ spotOffset ]     = _direction.x;
				spotDirections[ spotOffset + 1 ] = _direction.y;
				spotDirections[ spotOffset + 2 ] = _direction.z;
				spotAnglesCos[ spotLength ] = Math.cos( light.angle );
				spotExponents[ spotLength ] = light.exponent;
				spotLength += 1;
			} else if ( light instanceof THREE.HemisphereLight ) {
				hemiCount += 1;
				if ( ! light.visible ) continue;
				_direction.getPositionFromMatrix( light.matrixWorld );
				_direction.normalize();
												if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
				hemiOffset = hemiLength * 3;
				hemiPositions[ hemiOffset ]     = _direction.x;
				hemiPositions[ hemiOffset + 1 ] = _direction.y;
				hemiPositions[ hemiOffset + 2 ] = _direction.z;
				skyColor = light.color;
				groundColor = light.groundColor;
				if ( _this.gammaInput ) {
					intensitySq = intensity * intensity;
					setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq );
					setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq );
				} else {
					setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
					setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );
				}
				hemiLength += 1;
			}
		}
						for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;
		for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;
		for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;
		for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
		for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;
		zlights.directional.length = dirLength;
		zlights.point.length = pointLength;
		zlights.spot.length = spotLength;
		zlights.hemi.length = hemiLength;
		zlights.ambient[ 0 ] = r;
		zlights.ambient[ 1 ] = g;
		zlights.ambient[ 2 ] = b;
	};
		this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
		if ( cullFace === THREE.CullFaceNone ) {
			_gl.disable( _gl.CULL_FACE );
		} else {
			if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
				_gl.frontFace( _gl.CW );
			} else {
				_gl.frontFace( _gl.CCW );
			}
			if ( cullFace === THREE.CullFaceBack ) {
				_gl.cullFace( _gl.BACK );
			} else if ( cullFace === THREE.CullFaceFront ) {
				_gl.cullFace( _gl.FRONT );
			} else {
				_gl.cullFace( _gl.FRONT_AND_BACK );
			}
			_gl.enable( _gl.CULL_FACE );
		}
	};
	this.setMaterialFaces = function ( material ) {
		var doubleSided = material.side === THREE.DoubleSide;
		var flipSided = material.side === THREE.BackSide;
		if ( _oldDoubleSided !== doubleSided ) {
			if ( doubleSided ) {
				_gl.disable( _gl.CULL_FACE );
			} else {
				_gl.enable( _gl.CULL_FACE );
			}
			_oldDoubleSided = doubleSided;
		}
		if ( _oldFlipSided !== flipSided ) {
			if ( flipSided ) {
				_gl.frontFace( _gl.CW );
			} else {
				_gl.frontFace( _gl.CCW );
			}
			_oldFlipSided = flipSided;
		}
	};
	this.setDepthTest = function ( depthTest ) {
		if ( _oldDepthTest !== depthTest ) {
			if ( depthTest ) {
				_gl.enable( _gl.DEPTH_TEST );
			} else {
				_gl.disable( _gl.DEPTH_TEST );
			}
			_oldDepthTest = depthTest;
		}
	};
	this.setDepthWrite = function ( depthWrite ) {
		if ( _oldDepthWrite !== depthWrite ) {
			_gl.depthMask( depthWrite );
			_oldDepthWrite = depthWrite;
		}
	};
	function setLineWidth ( width ) {
		if ( width !== _oldLineWidth ) {
			_gl.lineWidth( width );
			_oldLineWidth = width;
		}
	};
	function setPolygonOffset ( polygonoffset, factor, units ) {
		if ( _oldPolygonOffset !== polygonoffset ) {
			if ( polygonoffset ) {
				_gl.enable( _gl.POLYGON_OFFSET_FILL );
			} else {
				_gl.disable( _gl.POLYGON_OFFSET_FILL );
			}
			_oldPolygonOffset = polygonoffset;
		}
		if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {
			_gl.polygonOffset( factor, units );
			_oldPolygonOffsetFactor = factor;
			_oldPolygonOffsetUnits = units;
		}
	};
	this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) {
		if ( blending !== _oldBlending ) {
			if ( blending === THREE.NoBlending ) {
				_gl.disable( _gl.BLEND );
			} else if ( blending === THREE.AdditiveBlending ) {
				_gl.enable( _gl.BLEND );
				_gl.blendEquation( _gl.FUNC_ADD );
				_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );
			} else if ( blending === THREE.SubtractiveBlending ) {
								_gl.enable( _gl.BLEND );
				_gl.blendEquation( _gl.FUNC_ADD );
				_gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );
			} else if ( blending === THREE.MultiplyBlending ) {
								_gl.enable( _gl.BLEND );
				_gl.blendEquation( _gl.FUNC_ADD );
				_gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );
			} else if ( blending === THREE.CustomBlending ) {
				_gl.enable( _gl.BLEND );
			} else {
				_gl.enable( _gl.BLEND );
				_gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
				_gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
			}
			_oldBlending = blending;
		}
		if ( blending === THREE.CustomBlending ) {
			if ( blendEquation !== _oldBlendEquation ) {
				_gl.blendEquation( paramThreeToGL( blendEquation ) );
				_oldBlendEquation = blendEquation;
			}
			if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) {
				_gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) );
				_oldBlendSrc = blendSrc;
				_oldBlendDst = blendDst;
			}
		} else {
			_oldBlendEquation = null;
			_oldBlendSrc = null;
			_oldBlendDst = null;
		}
	};
		function generateDefines ( defines ) {
		var value, chunk, chunks = [];
		for ( var d in defines ) {
			value = defines[ d ];
			if ( value === false ) continue;
			chunk = "#define " + d + " " + value;
			chunks.push( chunk );
		}
		return chunks.join( "\n" );
	};
		function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters ) {
		var p, pl, d, program, code;
		var chunks = [];
				if ( shaderID ) {
			chunks.push( shaderID );
		} else {
			chunks.push( fragmentShader );
			chunks.push( vertexShader );
		}
		for ( d in defines ) {
			chunks.push( d );
			chunks.push( defines[ d ] );
		}
		for ( p in parameters ) {
			chunks.push( p );
			chunks.push( parameters[ p ] );
		}
		code = chunks.join();
				for ( p = 0, pl = _programs.length; p < pl; p ++ ) {
			var programInfo = _programs[ p ];
			if ( programInfo.code === code ) {
								programInfo.usedTimes ++;
				return programInfo.program;
			}
		}
		var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
		if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
			shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
		} else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
			shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
		}
						var customDefines = generateDefines( defines );
				program = _gl.createProgram();
		var prefix_vertex = [
			"precision " + _precision + " float;",
			customDefines,
			_supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
			_this.gammaInput ? "#define GAMMA_INPUT" : "",
			_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
			_this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
			"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
			"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
			"#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
			"#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
			"#define MAX_SHADOWS " + parameters.maxShadows,
			"#define MAX_BONES " + parameters.maxBones,
			parameters.map ? "#define USE_MAP" : "",
			parameters.envMap ? "#define USE_ENVMAP" : "",
			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
			parameters.bumpMap ? "#define USE_BUMPMAP" : "",
			parameters.normalMap ? "#define USE_NORMALMAP" : "",
			parameters.specularMap ? "#define USE_SPECULARMAP" : "",
			parameters.vertexColors ? "#define USE_COLOR" : "",
			parameters.skinning ? "#define USE_SKINNING" : "",
			parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
			parameters.boneTextureWidth ? "#define N_BONE_PIXEL_X " + parameters.boneTextureWidth.toFixed( 1 ) : "",
			parameters.boneTextureHeight ? "#define N_BONE_PIXEL_Y " + parameters.boneTextureHeight.toFixed( 1 ) : "",
			parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
			parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
			parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
			parameters.wrapAround ? "#define WRAP_AROUND" : "",
			parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
			parameters.flipSided ? "#define FLIP_SIDED" : "",
			parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
			parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
			parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
			parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
			parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
			"uniform mat4 modelMatrix;",
			"uniform mat4 modelViewMatrix;",
			"uniform mat4 projectionMatrix;",
			"uniform mat4 viewMatrix;",
			"uniform mat3 normalMatrix;",
			"uniform vec3 cameraPosition;",
			"attribute vec3 position;",
			"attribute vec3 normal;",
			"attribute vec2 uv;",
			"attribute vec2 uv2;",
			"#ifdef USE_COLOR",
				"attribute vec3 color;",
			"#endif",
			"#ifdef USE_MORPHTARGETS",
				"attribute vec3 morphTarget0;",
				"attribute vec3 morphTarget1;",
				"attribute vec3 morphTarget2;",
				"attribute vec3 morphTarget3;",
				"#ifdef USE_MORPHNORMALS",
					"attribute vec3 morphNormal0;",
					"attribute vec3 morphNormal1;",
					"attribute vec3 morphNormal2;",
					"attribute vec3 morphNormal3;",
				"#else",
					"attribute vec3 morphTarget4;",
					"attribute vec3 morphTarget5;",
					"attribute vec3 morphTarget6;",
					"attribute vec3 morphTarget7;",
				"#endif",
			"#endif",
			"#ifdef USE_SKINNING",
				"attribute vec4 skinIndex;",
				"attribute vec4 skinWeight;",
			"#endif",
			""
		].join("\n");
		var prefix_fragment = [
			"precision " + _precision + " float;",
			( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
			customDefines,
			"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
			"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
			"#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
			"#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
			"#define MAX_SHADOWS " + parameters.maxShadows,
			parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
			_this.gammaInput ? "#define GAMMA_INPUT" : "",
			_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
			_this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
			( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
			( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
			parameters.map ? "#define USE_MAP" : "",
			parameters.envMap ? "#define USE_ENVMAP" : "",
			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
			parameters.bumpMap ? "#define USE_BUMPMAP" : "",
			parameters.normalMap ? "#define USE_NORMALMAP" : "",
			parameters.specularMap ? "#define USE_SPECULARMAP" : "",
			parameters.vertexColors ? "#define USE_COLOR" : "",
			parameters.metal ? "#define METAL" : "",
			parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
			parameters.wrapAround ? "#define WRAP_AROUND" : "",
			parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
			parameters.flipSided ? "#define FLIP_SIDED" : "",
			parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
			parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
			parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
			parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
			"uniform mat4 viewMatrix;",
			"uniform vec3 cameraPosition;",
			""
		].join("\n");
		var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );
		var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
		_gl.attachShader( program, glVertexShader );
		_gl.attachShader( program, glFragmentShader );
		_gl.linkProgram( program );
		if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
			console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
		}
				_gl.deleteShader( glFragmentShader );
		_gl.deleteShader( glVertexShader );
						program.uniforms = {};
		program.attributes = {};
		var identifiers, u, a, i;
				identifiers = [
			'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
			'morphTargetInfluences'
		];
		if ( parameters.useVertexTexture ) {
			identifiers.push( 'boneTexture' );
		} else {
			identifiers.push( 'boneGlobalMatrices' );
		}
		for ( u in uniforms ) {
			identifiers.push( u );
		}
		cacheUniformLocations( program, identifiers );
				identifiers = [
			"position", "normal", "uv", "uv2", "tangent", "color",
			"skinIndex", "skinWeight", "lineDistance"
		];
		for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {
			identifiers.push( "morphTarget" + i );
		}
		for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {
			identifiers.push( "morphNormal" + i );
		}
		for ( a in attributes ) {
			identifiers.push( a );
		}
		cacheAttributeLocations( program, identifiers );
		program.id = _programs_counter ++;
		_programs.push( { program: program, code: code, usedTimes: 1 } );
		_this.info.memory.programs = _programs.length;
		return program;
	};
		function cacheUniformLocations ( program, identifiers ) {
		var i, l, id;
		for( i = 0, l = identifiers.length; i < l; i ++ ) {
			id = identifiers[ i ];
			program.uniforms[ id ] = _gl.getUniformLocation( program, id );
		}
	};
	function cacheAttributeLocations ( program, identifiers ) {
		var i, l, id;
		for( i = 0, l = identifiers.length; i < l; i ++ ) {
			id = identifiers[ i ];
			program.attributes[ id ] = _gl.getAttribLocation( program, id );
		}
	};
	function addLineNumbers ( string ) {
		var chunks = string.split( "\n" );
		for ( var i = 0, il = chunks.length; i < il; i ++ ) {
									chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ];
		}
		return chunks.join( "\n" );
	};
	function getShader ( type, string ) {
		var shader;
		if ( type === "fragment" ) {
			shader = _gl.createShader( _gl.FRAGMENT_SHADER );
		} else if ( type === "vertex" ) {
			shader = _gl.createShader( _gl.VERTEX_SHADER );
		}
		_gl.shaderSource( shader, string );
		_gl.compileShader( shader );
		if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
			console.error( _gl.getShaderInfoLog( shader ) );
			console.error( addLineNumbers( string ) );
			return null;
		}
		return shader;
	};
		function isPowerOfTwo ( value ) {
		return ( value & ( value - 1 ) ) === 0;
	};
	function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
		if ( isImagePowerOfTwo ) {
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
		} else {
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
		}
		if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
			if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
				_gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
				texture.__oldAnisotropy = texture.anisotropy;
			}
		}
	};
	this.setTexture = function ( texture, slot ) {
		if ( texture.needsUpdate ) {
			if ( ! texture.__webglInit ) {
				texture.__webglInit = true;
				texture.addEventListener( 'dispose', onTextureDispose );
				texture.__webglTexture = _gl.createTexture();
				_this.info.memory.textures ++;
			}
			_gl.activeTexture( _gl.TEXTURE0 + slot );
			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
			var image = texture.image,
			isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
			glFormat = paramThreeToGL( texture.format ),
			glType = paramThreeToGL( texture.type );
			setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
			var mipmap, mipmaps = texture.mipmaps;
			 																if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
						mipmap = mipmaps[ i ];
						_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
					}
					texture.generateMipmaps = false;
				} else {
					_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
				}
			
			if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
			texture.needsUpdate = false;
			if ( texture.onUpdate ) texture.onUpdate();
		} else {
			_gl.activeTexture( _gl.TEXTURE0 + slot );
			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
		}
	};
	function clampToMaxSize ( image, maxSize ) {
		if ( image.width <= maxSize && image.height <= maxSize ) {
			return image;
		}
						var maxDimension = Math.max( image.width, image.height );
		var newWidth = Math.floor( image.width * maxSize / maxDimension );
		var newHeight = Math.floor( image.height * maxSize / maxDimension );
		var canvas = document.createElement( 'canvas' );
		canvas.width = newWidth;
		canvas.height = newHeight;
		var ctx = canvas.getContext( "2d" );
		ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
		return canvas;
	}
	function setCubeTexture ( texture, slot ) {
		if ( texture.image.length === 6 ) {
			if ( texture.needsUpdate ) {
				if ( ! texture.image.__webglTextureCube ) {
					texture.addEventListener( 'dispose', onTextureDispose );
					texture.image.__webglTextureCube = _gl.createTexture();
					_this.info.memory.textures ++;
				}
				_gl.activeTexture( _gl.TEXTURE0 + slot );
				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
				_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
				var isCompressed = texture instanceof THREE.CompressedTexture;
				var cubeImage = [];
				for ( var i = 0; i < 6; i ++ ) {
					if ( _this.autoScaleCubemaps && ! isCompressed ) {
						cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
					} else {
						cubeImage[ i ] = texture.image[ i ];
					}
				}
				var image = cubeImage[ 0 ],
				isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
				glFormat = paramThreeToGL( texture.format ),
				glType = paramThreeToGL( texture.type );
				setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
				for ( var i = 0; i < 6; i ++ ) {
					if ( isCompressed ) {
						var mipmap, mipmaps = cubeImage[ i ].mipmaps;
						for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
							mipmap = mipmaps[ j ];
							_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
						}
					} else {
						_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
					}
				}
				if ( texture.generateMipmaps && isImagePowerOfTwo ) {
					_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
				}
				texture.needsUpdate = false;
				if ( texture.onUpdate ) texture.onUpdate();
			} else {
				_gl.activeTexture( _gl.TEXTURE0 + slot );
				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
			}
		}
	};
	function setCubeTextureDynamic ( texture, slot ) {
		_gl.activeTexture( _gl.TEXTURE0 + slot );
		_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
	};
		function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
	};
	function setupRenderBuffer ( renderbuffer, renderTarget  ) {
		_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
		if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
		/* For some reason this is not working. Defaulting to RGBA4.
		} else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
		*/
		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
		} else {
			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
		}
	};
	this.setRenderTarget = function ( renderTarget ) {
		var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
		if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
			if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
			if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
			renderTarget.__webglTexture = _gl.createTexture();
			_this.info.memory.textures ++;
						var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ),
				glFormat = paramThreeToGL( renderTarget.format ),
				glType = paramThreeToGL( renderTarget.type );
			if ( isCube ) {
				renderTarget.__webglFramebuffer = [];
				renderTarget.__webglRenderbuffer = [];
				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
				for ( var i = 0; i < 6; i ++ ) {
					renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
					renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
					_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
					setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
					setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
				}
				if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
			} else {
				renderTarget.__webglFramebuffer = _gl.createFramebuffer();
				if ( renderTarget.shareDepthFrom ) {
					renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
				} else {
					renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
				}
				_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
				setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
				_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
				setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
				if ( renderTarget.shareDepthFrom ) {
					if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
					} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
					}
				} else {
					setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
				}
				if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
			}
						if ( isCube ) {
				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
			} else {
				_gl.bindTexture( _gl.TEXTURE_2D, null );
			}
			_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
		}
		var framebuffer, width, height, vx, vy;
		if ( renderTarget ) {
			if ( isCube ) {
				framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
			} else {
				framebuffer = renderTarget.__webglFramebuffer;
			}
			width = renderTarget.width;
			height = renderTarget.height;
			vx = 0;
			vy = 0;
		} else {
			framebuffer = null;
			width = _viewportWidth;
			height = _viewportHeight;
			vx = _viewportX;
			vy = _viewportY;
		}
		if ( framebuffer !== _currentFramebuffer ) {
			_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
			_gl.viewport( vx, vy, width, height );
			_currentFramebuffer = framebuffer;
		}
		_currentWidth = width;
		_currentHeight = height;
	};
	function updateRenderTargetMipmap ( renderTarget ) {
		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
			_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
			_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
			_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
		} else {
			_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
			_gl.generateMipmap( _gl.TEXTURE_2D );
			_gl.bindTexture( _gl.TEXTURE_2D, null );
		}
	};
		function filterFallback ( f ) {
		if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
			return _gl.NEAREST;
		}
		return _gl.LINEAR;
	};
		function paramThreeToGL ( p ) {
		if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
		if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
		if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
		if ( p === THREE.NearestFilter ) return _gl.NEAREST;
		if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
		if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
		if ( p === THREE.LinearFilter ) return _gl.LINEAR;
		if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
		if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
		if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
		if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
		if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
		if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
		if ( p === THREE.ByteType ) return _gl.BYTE;
		if ( p === THREE.ShortType ) return _gl.SHORT;
		if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
		if ( p === THREE.IntType ) return _gl.INT;
		if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
		if ( p === THREE.FloatType ) return _gl.FLOAT;
		if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
		if ( p === THREE.RGBFormat ) return _gl.RGB;
		if ( p === THREE.RGBAFormat ) return _gl.RGBA;
		if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
		if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
		if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
		if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
		if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
		if ( p === THREE.ZeroFactor ) return _gl.ZERO;
		if ( p === THREE.OneFactor ) return _gl.ONE;
		if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
		if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
		if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
		if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
		if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
		if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
		if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
		if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
		if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
		if ( _glExtensionCompressedTextureS3TC !== undefined ) {
			if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
			if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
			if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
			if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
		}
		return 0;
	};
		function allocateBones ( object ) {
		if ( _supportsBoneTextures && object && object.useVertexTexture ) {
			return 1024;
		} else {
																								var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
			var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
			var maxBones = nVertexMatrices;
			return maxBones;
		}
	};
	function allocateLights( lights ) {
		var dirLights = 0;
		var pointLights = 0;
		var spotLights = 0;
		var hemiLights = 0;
		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
			var light = lights[ l ];
			if ( light.onlyShadow ) continue;
			if ( light instanceof THREE.DirectionalLight ) dirLights ++;
			if ( light instanceof THREE.PointLight ) pointLights ++;
			if ( light instanceof THREE.SpotLight ) spotLights ++;
			if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
		}
		return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights };
	};
	function allocateShadows( lights ) {
		var maxShadows = 0;
		for ( var l = 0, ll = lights.length; l < ll; l++ ) {
			var light = lights[ l ];
			if ( ! light.castShadow ) continue;
			if ( light instanceof THREE.SpotLight ) maxShadows ++;
			if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
		}
		return maxShadows;
	};
		function initGL() {
		try {
			if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) {
				throw 'Error creating WebGL context.';
			}
		} catch ( error ) {
			console.error( error );
		}
		_glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
		_glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' );
		_glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
		_glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
		_glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
		if ( ! _glExtensionTextureFloat ) {
			console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
		}
		if ( ! _glExtensionStandardDerivatives ) {
			console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
		}
		if ( ! _glExtensionTextureFilterAnisotropic ) {
			console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
		}
		if ( ! _glExtensionCompressedTextureS3TC ) {
			console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
		}
		if ( _gl.getShaderPrecisionFormat === undefined ) {
			_gl.getShaderPrecisionFormat = function() {
				return {
					"rangeMin"  : 1,
					"rangeMax"  : 1,
					"precision" : 1
				};
			}
		}
	};
	function setDefaultGLState () {
		_gl.clearColor( 0, 0, 0, 1 );
		_gl.clearDepth( 1 );
		_gl.clearStencil( 0 );
		_gl.enable( _gl.DEPTH_TEST );
		_gl.depthFunc( _gl.LEQUAL );
		_gl.frontFace( _gl.CCW );
		_gl.cullFace( _gl.BACK );
		_gl.enable( _gl.CULL_FACE );
		_gl.enable( _gl.BLEND );
		_gl.blendEquation( _gl.FUNC_ADD );
		_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
		_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
	};
		this.shadowMapPlugin = new THREE.ShadowMapPlugin();
	this.addPrePlugin( this.shadowMapPlugin );
	this.addPostPlugin( new THREE.SpritePlugin() );
	this.addPostPlugin( new THREE.LensFlarePlugin() );
};
THREE.WebGLRenderTargetCube = function ( width, height, options ) {
	THREE.WebGLRenderTarget.call( this, width, height, options );
	this.activeCubeFace = 0; };
THREE.ImageUtils = {
	crossOrigin: 'anonymous',
	loadTexture: function ( url, mapping, onLoad, onError ) {
		var image = new Image();
		var texture = new THREE.Texture( image, mapping );
		var loader = new THREE.ImageLoader();
		loader.crossOrigin = this.crossOrigin;
		loader.load( url, function ( image ) {
			texture.image = image;
			texture.needsUpdate = true;
			if ( onLoad ) onLoad( texture );
		} );
		texture.sourceFile = url;
		return texture;
	},
	loadCompressedTexture: function ( url, mapping, onLoad, onError ) {
		var texture = new THREE.CompressedTexture();
		texture.mapping = mapping;
		var request = new XMLHttpRequest();
		request.onload = function () {
			var buffer = request.response;
			var dds = THREE.ImageUtils.parseDDS( buffer, true );
			texture.format = dds.format;
			texture.mipmaps = dds.mipmaps;
			texture.image.width = dds.width;
			texture.image.height = dds.height;
												texture.generateMipmaps = false;
			texture.needsUpdate = true;
			if ( onLoad ) onLoad( texture );
		}
		request.onerror = onError;
		request.open( 'GET', url, true );
		request.responseType = "arraybuffer";
		request.send( null );
		return texture;
	},
	loadTextureCube: function ( array, mapping, onLoad, onError ) {
		var images = [];
		images.loadCount = 0;
		var texture = new THREE.Texture();
		texture.image = images;
		if ( mapping !== undefined ) texture.mapping = mapping;
				texture.flipY = false;
		for ( var i = 0, il = array.length; i < il; ++ i ) {
			var cubeImage = new Image();
			images[ i ] = cubeImage;
			cubeImage.onload = function () {
				images.loadCount += 1;
				if ( images.loadCount === 6 ) {
					texture.needsUpdate = true;
					if ( onLoad ) onLoad( texture );
				}
			};
			cubeImage.onerror = onError;
			cubeImage.crossOrigin = this.crossOrigin;
			cubeImage.src = array[ i ];
		}
		return texture;
	},
	loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) {
		var images = [];
		images.loadCount = 0;
		var texture = new THREE.CompressedTexture();
		texture.image = images;
		if ( mapping !== undefined ) texture.mapping = mapping;
						texture.flipY = false;
						texture.generateMipmaps = false;
		var generateCubeFaceCallback = function ( rq, img ) {
			return function () {
				var buffer = rq.response;
				var dds = THREE.ImageUtils.parseDDS( buffer, true );
				img.format = dds.format;
				img.mipmaps = dds.mipmaps;
				img.width = dds.width;
				img.height = dds.height;
				images.loadCount += 1;
				if ( images.loadCount === 6 ) {
					texture.format = dds.format;
					texture.needsUpdate = true;
					if ( onLoad ) onLoad( texture );
				}
			}
		}
				if ( array instanceof Array ) {
			for ( var i = 0, il = array.length; i < il; ++ i ) {
				var cubeImage = {};
				images[ i ] = cubeImage;
				var request = new XMLHttpRequest();
				request.onload = generateCubeFaceCallback( request, cubeImage );
				request.onerror = onError;
				var url = array[ i ];
				request.open( 'GET', url, true );
				request.responseType = "arraybuffer";
				request.send( null );
			}
				} else {
			var url = array;
			var request = new XMLHttpRequest();
			request.onload = function( ) {
				var buffer = request.response;
				var dds = THREE.ImageUtils.parseDDS( buffer, true );
				if ( dds.isCubemap ) {
					var faces = dds.mipmaps.length / dds.mipmapCount;
					for ( var f = 0; f < faces; f ++ ) {
						images[ f ] = { mipmaps : [] };
						for ( var i = 0; i < dds.mipmapCount; i ++ ) {
							images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] );
							images[ f ].format = dds.format;
							images[ f ].width = dds.width;
							images[ f ].height = dds.height;
						}
					}
					texture.format = dds.format;
					texture.needsUpdate = true;
					if ( onLoad ) onLoad( texture );
				}
			}
			request.onerror = onError;
			request.open( 'GET', url, true );
			request.responseType = "arraybuffer";
			request.send( null );
		}
		return texture;
	},
	parseDDS: function ( buffer, loadMipmaps ) {
		var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 };
										var DDS_MAGIC = 0x20534444;
		var DDSD_CAPS = 0x1,
			DDSD_HEIGHT = 0x2,
			DDSD_WIDTH = 0x4,
			DDSD_PITCH = 0x8,
			DDSD_PIXELFORMAT = 0x1000,
			DDSD_MIPMAPCOUNT = 0x20000,
			DDSD_LINEARSIZE = 0x80000,
			DDSD_DEPTH = 0x800000;
		var DDSCAPS_COMPLEX = 0x8,
			DDSCAPS_MIPMAP = 0x400000,
			DDSCAPS_TEXTURE = 0x1000;
		var DDSCAPS2_CUBEMAP = 0x200,
			DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
			DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
			DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
			DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
			DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
			DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
			DDSCAPS2_VOLUME = 0x200000;
		var DDPF_ALPHAPIXELS = 0x1,
			DDPF_ALPHA = 0x2,
			DDPF_FOURCC = 0x4,
			DDPF_RGB = 0x40,
			DDPF_YUV = 0x200,
			DDPF_LUMINANCE = 0x20000;
		function fourCCToInt32( value ) {
			return value.charCodeAt(0) +
				(value.charCodeAt(1) << 8) +
				(value.charCodeAt(2) << 16) +
				(value.charCodeAt(3) << 24);
		}
		function int32ToFourCC( value ) {
			return String.fromCharCode(
				value & 0xff,
				(value >> 8) & 0xff,
				(value >> 16) & 0xff,
				(value >> 24) & 0xff
			);
		}
		var FOURCC_DXT1 = fourCCToInt32("DXT1");
		var FOURCC_DXT3 = fourCCToInt32("DXT3");
		var FOURCC_DXT5 = fourCCToInt32("DXT5");
		var headerLengthInt = 31; 				var off_magic = 0;
		var off_size = 1;
		var off_flags = 2;
		var off_height = 3;
		var off_width = 4;
		var off_mipmapCount = 7;
		var off_pfFlags = 20;
		var off_pfFourCC = 21;
		var off_caps = 27;
		var off_caps2 = 28;
		var off_caps3 = 29;
		var off_caps4 = 30;
				var header = new Int32Array( buffer, 0, headerLengthInt );
		if ( header[ off_magic ] !== DDS_MAGIC ) {
			console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" );
			return dds;
		}
		if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {
			console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" );
			return dds;
		}
		var blockBytes;
		var fourCC = header[ off_pfFourCC ];
		switch ( fourCC ) {
			case FOURCC_DXT1:
				blockBytes = 8;
				dds.format = THREE.RGB_S3TC_DXT1_Format;
				break;
			case FOURCC_DXT3:
				blockBytes = 16;
				dds.format = THREE.RGBA_S3TC_DXT3_Format;
				break;
			case FOURCC_DXT5:
				blockBytes = 16;
				dds.format = THREE.RGBA_S3TC_DXT5_Format;
				break;
			default:
				console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) );
				return dds;
		}
		dds.mipmapCount = 1;
		if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {
			dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );
		}
				dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false;
		dds.width = header[ off_width ];
		dds.height = header[ off_height ];
		var dataOffset = header[ off_size ] + 4;
				var width = dds.width;
		var height = dds.height;
		var faces = dds.isCubemap ? 6 : 1;
		for ( var face = 0; face < faces; face ++ ) {
			for ( var i = 0; i < dds.mipmapCount; i ++ ) {
				var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
				var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
				var mipmap = { "data": byteArray, "width": width, "height": height };
				dds.mipmaps.push( mipmap );
				dataOffset += dataLength;
				width = Math.max( width * 0.5, 1 );
				height = Math.max( height * 0.5, 1 );
			}
			width = dds.width;
			height = dds.height;
		}
		return dds;
	},
	getNormalMap: function ( image, depth ) {
				var cross = function ( a, b ) {
			return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];
		}
		var subtract = function ( a, b ) {
			return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];
		}
		var normalize = function ( a ) {
			var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
			return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];
		}
		depth = depth | 1;
		var width = image.width;
		var height = image.height;
		var canvas = document.createElement( 'canvas' );
		canvas.width = width;
		canvas.height = height;
		var context = canvas.getContext( '2d' );
		context.drawImage( image, 0, 0 );
		var data = context.getImageData( 0, 0, width, height ).data;
		var imageData = context.createImageData( width, height );
		var output = imageData.data;
		for ( var x = 0; x < width; x ++ ) {
			for ( var y = 0; y < height; y ++ ) {
				var ly = y - 1 < 0 ? 0 : y - 1;
				var uy = y + 1 > height - 1 ? height - 1 : y + 1;
				var lx = x - 1 < 0 ? 0 : x - 1;
				var ux = x + 1 > width - 1 ? width - 1 : x + 1;
				var points = [];
				var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
				points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
				points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
				points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
				points.push( [  1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
				points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
				points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
				points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
				points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );
				var normals = [];
				var num_points = points.length;
				for ( var i = 0; i < num_points; i ++ ) {
					var v1 = points[ i ];
					var v2 = points[ ( i + 1 ) % num_points ];
					v1 = subtract( v1, origin );
					v2 = subtract( v2, origin );
					normals.push( normalize( cross( v1, v2 ) ) );
				}
				var normal = [ 0, 0, 0 ];
				for ( var i = 0; i < normals.length; i ++ ) {
					normal[ 0 ] += normals[ i ][ 0 ];
					normal[ 1 ] += normals[ i ][ 1 ];
					normal[ 2 ] += normals[ i ][ 2 ];
				}
				normal[ 0 ] /= normals.length;
				normal[ 1 ] /= normals.length;
				normal[ 2 ] /= normals.length;
				var idx = ( y * width + x ) * 4;
				output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
				output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
				output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
				output[ idx + 3 ] = 255;
			}
		}
		context.putImageData( imageData, 0, 0 );
		return canvas;
	},
	generateDataTexture: function ( width, height, color ) {
		var size = width * height;
		var data = new Uint8Array( 3 * size );
		var r = Math.floor( color.r * 255 );
		var g = Math.floor( color.g * 255 );
		var b = Math.floor( color.b * 255 );
		for ( var i = 0; i < size; i ++ ) {
			data[ i * 3 ] 	  = r;
			data[ i * 3 + 1 ] = g;
			data[ i * 3 + 2 ] = b;
		}
		var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
		texture.needsUpdate = true;
		return texture;
	}
};


THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) {

	THREE.Geometry.call( this );

	this.width = width;
	this.height = height;

	this.widthSegments = widthSegments || 1;
	this.heightSegments = heightSegments || 1;

	var ix, iz;
	var width_half = width / 2;
	var height_half = height / 2;

	var gridX = this.widthSegments;
	var gridZ = this.heightSegments;

	var gridX1 = gridX + 1;
	var gridZ1 = gridZ + 1;

	var segment_width = this.width / gridX;
	var segment_height = this.height / gridZ;

	var normal = new THREE.Vector3( 0, 0, 1 );

	for ( iz = 0; iz < gridZ1; iz ++ ) {

		for ( ix = 0; ix < gridX1; ix ++ ) {

			var x = ix * segment_width - width_half;
			var y = iz * segment_height - height_half;

			this.vertices.push( new THREE.Vector3( x, - y, 0 ) );

		}

	}

	for ( iz = 0; iz < gridZ; iz ++ ) {

		for ( ix = 0; ix < gridX; ix ++ ) {

			var a = ix + gridX1 * iz;
			var b = ix + gridX1 * ( iz + 1 );
			var c = ( ix + 1 ) + gridX1 * ( iz + 1 );
			var d = ( ix + 1 ) + gridX1 * iz;

			var face = new THREE.Face4( a, b, c, d );
			face.normal.copy( normal );
			face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() );

			this.faces.push( face );
			this.faceVertexUvs[ 0 ].push( [
				new THREE.Vector2( ix / gridX, 1 - iz / gridZ ),
				new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ),
				new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ),
				new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ )
			] );

		}

	}

	this.computeCentroids();

};

THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype );


THREE.SphereGeometry = function ( isRectangular, radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength, cx, cy ) {
	THREE.Geometry.call( this );
	this.radius = radius = radius || 50;
	
	if(isRectangular){
		this.widthSegments = widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
		this.heightSegments = heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
		this.phiStart = phiStart = phiStart !== undefined ? phiStart : 0;
		this.phiLength = phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
		this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0;
		this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
		var x, y, vertices = [], uvs = [];
		for ( y = 0; y <= heightSegments; y ++ ) {
			var verticesRow = [];
			var uvsRow = [];
			for ( x = 0; x <= widthSegments; x ++ ) {
				var u = x / widthSegments;
				var v = y / heightSegments;
				var vertex = new THREE.Vector3();
				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
				this.vertices.push( vertex );
				verticesRow.push( this.vertices.length - 1 );
				uvsRow.push( new THREE.Vector2( u, 1 - v ) );
			}
			vertices.push( verticesRow );
			uvs.push( uvsRow );
		}
		for ( y = 0; y < this.heightSegments; y ++ ) {
			for ( x = 0; x < this.widthSegments; x ++ ) {
				var v1 = vertices[ y ][ x + 1 ];
				var v2 = vertices[ y ][ x ];
				var v3 = vertices[ y + 1 ][ x ];
				var v4 = vertices[ y + 1 ][ x + 1 ];
				var n1 = this.vertices[ v1 ].clone().normalize();
				var n2 = this.vertices[ v2 ].clone().normalize();
				var n3 = this.vertices[ v3 ].clone().normalize();
				var n4 = this.vertices[ v4 ].clone().normalize();
				var uv1 = uvs[ y ][ x + 1 ].clone();
				var uv2 = uvs[ y ][ x ].clone();
				var uv3 = uvs[ y + 1 ][ x ].clone();
				var uv4 = uvs[ y + 1 ][ x + 1 ].clone();
				if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) {
					this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) );
					this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] );
				} else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) {
					this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
					this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
				} else {
					this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) );
					this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] );
				}
			}
		}
		this.computeCentroids();
		this.computeFaceNormals();
		this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
	}else{
		var minRadius = 0.5
		var maxRadius = -0.5
		
		phiStart = phiStart !== undefined ? phiStart : 0;
		phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
		thetaStart = thetaStart !== undefined ? thetaStart : 0;
		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
		var segmentsX = Math.max( 3, Math.floor( widthSegments ) || 8 );
		var segmentsY = Math.max( 2, Math.floor( heightSegments ) || 6 );
		
		var rMin = -phiStart + 180 * Math.PI / 180;
		var rMax = thetaStart - 180 * Math.PI / 180;
		
		
		var x, y, vertices = [], uvs = [];
		for ( y = 0; y <= segmentsY; y ++ ) {
			var verticesRow = [];
			var uvsRow = [];
			
			
			var amplitutde = ( ( maxRadius - minRadius ) * ( y / segmentsY ) ) + minRadius;
			var latitudeAngle = ( Math.PI - rMin - rMax ) * ( y /  segmentsY ) + rMax;
			var sinLatAngle = Math.sin( latitudeAngle );
			
			var cosLatAngle = Math.cos( latitudeAngle );
			
			for ( x = 0; x <= segmentsX; x ++ ) {
				var longitudeAngle = ( 2 * Math.PI * ( x / segmentsX ) );
				var sinLongAngle = Math.sin(longitudeAngle);
				var cosLongAngle = Math.cos(longitudeAngle);
				
				var u = 0.75 * sinLongAngle;
				var v = cosLongAngle;
				u *= amplitutde;
				v *= amplitutde;
				
				
				u += cx;
				v += cy;
				var vertex = new THREE.Vector3();
				
				
				
				
				vertex.x = radius * sinLatAngle * cosLongAngle;
				vertex.y = -radius * cosLatAngle;
				vertex.z = radius * sinLatAngle * sinLongAngle;
				
				this.vertices.push( vertex );
				verticesRow.push( this.vertices.length - 1 );
				uvsRow.push( new THREE.UV( u , v ) );
			}
			vertices.push( verticesRow );
			uvs.push( uvsRow );
		}
		for ( y = 0; y < segmentsY; y ++ ) {
			for ( x = 0; x < segmentsX; x ++ ) {
				var v1 = vertices[ y ][ x + 1 ];
				var v2 = vertices[ y ][ x ];
				var v3 = vertices[ y + 1 ][ x ];
				var v4 = vertices[ y + 1 ][ x + 1 ];
				var n1 = this.vertices[ v1 ].clone().normalize();
				var n2 = this.vertices[ v2 ].clone().normalize();
				var n3 = this.vertices[ v3 ].clone().normalize();
				var n4 = this.vertices[ v4 ].clone().normalize();
				var uv1 = uvs[ y ][ x + 1 ].clone();
				var uv2 = uvs[ y ][ x ].clone();
				var uv3 = uvs[ y + 1 ][ x ].clone();
				var uv4 = uvs[ y + 1 ][ x + 1 ].clone();
				if ( Math.abs( this.vertices[ v1 ].y ) == radius ) {
					this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) );
					this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] );
				} else if ( Math.abs( this.vertices[ v3 ].y ) ==  radius ) {
					this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
					this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
				} else {
					this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) );
					this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] );
				}
			}
		}
		this.computeCentroids();
		this.computeFaceNormals();
		this.boundingSphere = { radius: radius };
	}
};
THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.LensFlare = function ( texture, size, distance, blending, color ) {
	THREE.Object3D.call( this );
	this.lensFlares = [];
	this.positionScreen = new THREE.Vector3();
	this.customUpdateCallback = undefined;
	if( texture !== undefined ) {
		this.add( texture, size, distance, blending, color );
	}
};
THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype );
THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) {
	if( size === undefined ) size = -1;
	if( distance === undefined ) distance = 0;
	if( opacity === undefined ) opacity = 1;
	if( color === undefined ) color = new THREE.Color( 0xffffff );
	if( blending === undefined ) blending = THREE.NormalBlending;
	distance = Math.min( distance, Math.max( 0, distance ) );
	this.lensFlares.push( { texture: texture, 					                    size: size, 						                    distance: distance, 				                    x: 0, y: 0, z: 0,					                    scale: 1, 							                    rotation: 1, 						                    opacity: opacity,										color: color,						                    blending: blending } );		};
THREE.LensFlare.prototype.updateLensFlares = function () {
	var f, fl = this.lensFlares.length;
	var flare;
	var vecX = -this.positionScreen.x * 2;
	var vecY = -this.positionScreen.y * 2;
	for( f = 0; f < fl; f ++ ) {
		flare = this.lensFlares[ f ];
		flare.x = this.positionScreen.x + vecX * flare.distance;
		flare.y = this.positionScreen.y + vecY * flare.distance;
		flare.wantedRotation = flare.x * Math.PI * 0.25;
		flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;
	}
};
THREE.LensFlarePlugin = function () {
	var _gl, _renderer, _precision, _lensFlare = {};
	this.init = function ( renderer ) {
		_gl = renderer.context;
		_renderer = renderer;
		_precision = renderer.getPrecision();
		_lensFlare.vertices = new Float32Array( 8 + 8 );
		_lensFlare.faces = new Uint16Array( 6 );
		var i = 0;
		_lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1;			_lensFlare.vertices[ i++ ] = 0;  _lensFlare.vertices[ i++ ] = 0;			_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = -1;
		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 0;
		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 1;
		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 1;
		_lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1;
		_lensFlare.vertices[ i++ ] = 0;  _lensFlare.vertices[ i++ ] = 1;
		i = 0;
		_lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2;
		_lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3;
				_lensFlare.vertexBuffer     = _gl.createBuffer();
		_lensFlare.elementBuffer    = _gl.createBuffer();
		_gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
		_gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW );
		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW );
				_lensFlare.tempTexture      = _gl.createTexture();
		_lensFlare.occlusionTexture = _gl.createTexture();
		_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
		_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
		_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
		_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
		if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) {
			_lensFlare.hasVertexTexture = false;
			_lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision );
		} else {
			_lensFlare.hasVertexTexture = true;
			_lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision );
		}
		_lensFlare.attributes = {};
		_lensFlare.uniforms = {};
		_lensFlare.attributes.vertex       = _gl.getAttribLocation ( _lensFlare.program, "position" );
		_lensFlare.attributes.uv           = _gl.getAttribLocation ( _lensFlare.program, "uv" );
		_lensFlare.uniforms.renderType     = _gl.getUniformLocation( _lensFlare.program, "renderType" );
		_lensFlare.uniforms.map            = _gl.getUniformLocation( _lensFlare.program, "map" );
		_lensFlare.uniforms.occlusionMap   = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" );
		_lensFlare.uniforms.opacity        = _gl.getUniformLocation( _lensFlare.program, "opacity" );
		_lensFlare.uniforms.color          = _gl.getUniformLocation( _lensFlare.program, "color" );
		_lensFlare.uniforms.scale          = _gl.getUniformLocation( _lensFlare.program, "scale" );
		_lensFlare.uniforms.rotation       = _gl.getUniformLocation( _lensFlare.program, "rotation" );
		_lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" );
	};
	/*
	 * Render lens flares
	 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
	 *         reads these back and calculates occlusion.
	 *         Then _lensFlare.update_lensFlares() is called to re-position and
	 *         update transparency of flares. Then they are rendered.
	 *
	 */
	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
		var flares = scene.__webglFlares,
			nFlares = flares.length;
		if ( ! nFlares ) return;
		var tempPosition = new THREE.Vector3();
		var invAspect = viewportHeight / viewportWidth,
			halfViewportWidth = viewportWidth * 0.5,
			halfViewportHeight = viewportHeight * 0.5;
		var size = 16 / viewportHeight,
			scale = new THREE.Vector2( size * invAspect, size );
		var screenPosition = new THREE.Vector3( 1, 1, 0 ),
			screenPositionPixels = new THREE.Vector2( 1, 1 );
		var uniforms = _lensFlare.uniforms,
			attributes = _lensFlare.attributes;
				_gl.useProgram( _lensFlare.program );
		_gl.enableVertexAttribArray( _lensFlare.attributes.vertex );
		_gl.enableVertexAttribArray( _lensFlare.attributes.uv );
						_gl.uniform1i( uniforms.occlusionMap, 0 );
		_gl.uniform1i( uniforms.map, 1 );
		_gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
		_gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 );
		_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
		_gl.disable( _gl.CULL_FACE );
		_gl.depthMask( false );
		var i, j, jl, flare, sprite;
		for ( i = 0; i < nFlares; i ++ ) {
			size = 16 / viewportHeight;
			scale.set( size * invAspect, size );
						flare = flares[ i ];
			tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );
			tempPosition.applyMatrix4( camera.matrixWorldInverse );
			tempPosition.applyProjection( camera.projectionMatrix );
						screenPosition.copy( tempPosition )
			screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth;
			screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight;
						if ( _lensFlare.hasVertexTexture || (
				screenPositionPixels.x > 0 &&
				screenPositionPixels.x < viewportWidth &&
				screenPositionPixels.y > 0 &&
				screenPositionPixels.y < viewportHeight ) ) {
								_gl.activeTexture( _gl.TEXTURE1 );
				_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
				_gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
								_gl.uniform1i( uniforms.renderType, 0 );
				_gl.uniform2f( uniforms.scale, scale.x, scale.y );
				_gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
				_gl.disable( _gl.BLEND );
				_gl.enable( _gl.DEPTH_TEST );
				_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
								_gl.activeTexture( _gl.TEXTURE0 );
				_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
				_gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
								_gl.uniform1i( uniforms.renderType, 1 );
				_gl.disable( _gl.DEPTH_TEST );
				_gl.activeTexture( _gl.TEXTURE1 );
				_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
				_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
								flare.positionScreen.copy( screenPosition )
				if ( flare.customUpdateCallback ) {
					flare.customUpdateCallback( flare );
				} else {
					flare.updateLensFlares();
				}
								_gl.uniform1i( uniforms.renderType, 2 );
				_gl.enable( _gl.BLEND );
				for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
					sprite = flare.lensFlares[ j ];
					if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
						screenPosition.x = sprite.x;
						screenPosition.y = sprite.y;
						screenPosition.z = sprite.z;
						size = sprite.size * sprite.scale / viewportHeight;
						scale.x = size * invAspect;
						scale.y = size;
						_gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
						_gl.uniform2f( uniforms.scale, scale.x, scale.y );
						_gl.uniform1f( uniforms.rotation, sprite.rotation );
						_gl.uniform1f( uniforms.opacity, sprite.opacity );
						_gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
						_renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
						_renderer.setTexture( sprite.texture, 1 );
						_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
					}
				}
			}
		}
				_gl.enable( _gl.CULL_FACE );
		_gl.enable( _gl.DEPTH_TEST );
		_gl.depthMask( true );
	};
	function createProgram ( shader, precision ) {
		var program = _gl.createProgram();
		var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
		var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
		var prefix = "precision " + precision + " float;\n";
		_gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
		_gl.shaderSource( vertexShader, prefix + shader.vertexShader );
		_gl.compileShader( fragmentShader );
		_gl.compileShader( vertexShader );
		_gl.attachShader( program, fragmentShader );
		_gl.attachShader( program, vertexShader );
		_gl.linkProgram( program );
		return program;
	};
};
THREE.ShadowMapPlugin = function () {
	var _gl,
	_renderer,
	_depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
	_frustum = new THREE.Frustum(),
	_projScreenMatrix = new THREE.Matrix4(),
	_min = new THREE.Vector3(),
	_max = new THREE.Vector3(),
	_matrixPosition = new THREE.Vector3();
	this.init = function ( renderer ) {
		_gl = renderer.context;
		_renderer = renderer;
		var depthShader = THREE.ShaderLib[ "depthRGBA" ];
		var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
		_depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
		_depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
		_depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } );
		_depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } );
		_depthMaterial._shadowPass = true;
		_depthMaterialMorph._shadowPass = true;
		_depthMaterialSkin._shadowPass = true;
		_depthMaterialMorphSkin._shadowPass = true;
	};
	this.render = function ( scene, camera ) {
		if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return;
		this.update( scene, camera );
	};
	this.update = function ( scene, camera ) {
		var i, il, j, jl, n,
		shadowMap, shadowMatrix, shadowCamera,
		program, buffer, material,
		webglObject, object, light,
		renderList,
		lights = [],
		k = 0,
		fog = null;
				_gl.clearColor( 1, 1, 1, 1 );
		_gl.disable( _gl.BLEND );
		_gl.enable( _gl.CULL_FACE );
		_gl.frontFace( _gl.CCW );
		if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
			_gl.cullFace( _gl.FRONT );
		} else {
			_gl.cullFace( _gl.BACK );
		}
		_renderer.setDepthTest( true );
								for ( i = 0, il = scene.__lights.length; i < il; i ++ ) {
			light = scene.__lights[ i ];
			if ( ! light.castShadow ) continue;
			if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) {
				for ( n = 0; n < light.shadowCascadeCount; n ++ ) {
					var virtualLight;
					if ( ! light.shadowCascadeArray[ n ] ) {
						virtualLight = createVirtualLight( light, n );
						virtualLight.originalCamera = camera;
						var gyro = new THREE.Gyroscope();
						gyro.position = light.shadowCascadeOffset;
						gyro.add( virtualLight );
						gyro.add( virtualLight.target );
						camera.add( gyro );
						light.shadowCascadeArray[ n ] = virtualLight;
						console.log( "Created virtualLight", virtualLight );
					} else {
						virtualLight = light.shadowCascadeArray[ n ];
					}
					updateVirtualLight( light, n );
					lights[ k ] = virtualLight;
					k ++;
				}
			} else {
				lights[ k ] = light;
				k ++;
			}
		}
				for ( i = 0, il = lights.length; i < il; i ++ ) {
			light = lights[ i ];
			if ( ! light.shadowMap ) {
				var shadowFilter = THREE.LinearFilter;
				if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) {
					shadowFilter = THREE.NearestFilter;
				}
				var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
				light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
				light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
				light.shadowMatrix = new THREE.Matrix4();
			}
			if ( ! light.shadowCamera ) {
				if ( light instanceof THREE.SpotLight ) {
					light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );
				} else if ( light instanceof THREE.DirectionalLight ) {
					light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );
				} else {
					console.error( "Unsupported light type for shadow" );
					continue;
				}
				scene.add( light.shadowCamera );
				if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
			}
			if ( light.shadowCameraVisible && ! light.cameraHelper ) {
				light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
				light.shadowCamera.add( light.cameraHelper );
			}
			if ( light.isVirtual && virtualLight.originalCamera == camera ) {
				updateShadowCamera( camera, light );
			}
			shadowMap = light.shadowMap;
			shadowMatrix = light.shadowMatrix;
			shadowCamera = light.shadowCamera;
			shadowCamera.position.getPositionFromMatrix( light.matrixWorld );
			_matrixPosition.getPositionFromMatrix( light.target.matrixWorld );
			shadowCamera.lookAt( _matrixPosition );
			shadowCamera.updateMatrixWorld();
			shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
			if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;
			if ( light.shadowCameraVisible ) light.cameraHelper.update();
						shadowMatrix.set( 0.5, 0.0, 0.0, 0.5,
							  0.0, 0.5, 0.0, 0.5,
							  0.0, 0.0, 0.5, 0.5,
							  0.0, 0.0, 0.0, 1.0 );
			shadowMatrix.multiply( shadowCamera.projectionMatrix );
			shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
						_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
			_frustum.setFromMatrix( _projScreenMatrix );
						_renderer.setRenderTarget( shadowMap );
			_renderer.clear();
						renderList = scene.__webglObjects;
			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
				webglObject = renderList[ j ];
				object = webglObject.object;
				webglObject.render = false;
				if ( object.visible && object.castShadow ) {
					if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
						object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
						webglObject.render = true;
					}
				}
			}
						var objectMaterial, useMorphing, useSkinning;
			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
				webglObject = renderList[ j ];
				if ( webglObject.render ) {
					object = webglObject.object;
					buffer = webglObject.buffer;
																																								objectMaterial = getObjectMaterial( object );
					useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
					useSkinning = objectMaterial.skinning;
					if ( object.customDepthMaterial ) {
						material = object.customDepthMaterial;
					} else if ( useSkinning ) {
						material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
					} else if ( useMorphing ) {
						material = _depthMaterialMorph;
					} else {
						material = _depthMaterial;
					}
					if ( buffer instanceof THREE.BufferGeometry ) {
						_renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );
					} else {
						_renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object );
					}
				}
			}
						renderList = scene.__webglObjectsImmediate;
			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
				webglObject = renderList[ j ];
				object = webglObject.object;
				if ( object.visible && object.castShadow ) {
					object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
					_renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object );
				}
			}
		}
				var clearColor = _renderer.getClearColor(),
		clearAlpha = _renderer.getClearAlpha();
		_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
		_gl.enable( _gl.BLEND );
		if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
			_gl.cullFace( _gl.BACK );
		}
	};
	function createVirtualLight( light, cascade ) {
		var virtualLight = new THREE.DirectionalLight();
		virtualLight.isVirtual = true;
		virtualLight.onlyShadow = true;
		virtualLight.castShadow = true;
		virtualLight.shadowCameraNear = light.shadowCameraNear;
		virtualLight.shadowCameraFar = light.shadowCameraFar;
		virtualLight.shadowCameraLeft = light.shadowCameraLeft;
		virtualLight.shadowCameraRight = light.shadowCameraRight;
		virtualLight.shadowCameraBottom = light.shadowCameraBottom;
		virtualLight.shadowCameraTop = light.shadowCameraTop;
		virtualLight.shadowCameraVisible = light.shadowCameraVisible;
		virtualLight.shadowDarkness = light.shadowDarkness;
		virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
		virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ];
		virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ];
		virtualLight.pointsWorld = [];
		virtualLight.pointsFrustum = [];
		var pointsWorld = virtualLight.pointsWorld,
			pointsFrustum = virtualLight.pointsFrustum;
		for ( var i = 0; i < 8; i ++ ) {
			pointsWorld[ i ] = new THREE.Vector3();
			pointsFrustum[ i ] = new THREE.Vector3();
		}
		var nearZ = light.shadowCascadeNearZ[ cascade ];
		var farZ = light.shadowCascadeFarZ[ cascade ];
		pointsFrustum[ 0 ].set( -1, -1, nearZ );
		pointsFrustum[ 1 ].set(  1, -1, nearZ );
		pointsFrustum[ 2 ].set( -1,  1, nearZ );
		pointsFrustum[ 3 ].set(  1,  1, nearZ );
		pointsFrustum[ 4 ].set( -1, -1, farZ );
		pointsFrustum[ 5 ].set(  1, -1, farZ );
		pointsFrustum[ 6 ].set( -1,  1, farZ );
		pointsFrustum[ 7 ].set(  1,  1, farZ );
		return virtualLight;
	}
		function updateVirtualLight( light, cascade ) {
		var virtualLight = light.shadowCascadeArray[ cascade ];
		virtualLight.position.copy( light.position );
		virtualLight.target.position.copy( light.target.position );
		virtualLight.lookAt( virtualLight.target );
		virtualLight.shadowCameraVisible = light.shadowCameraVisible;
		virtualLight.shadowDarkness = light.shadowDarkness;
		virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
		var nearZ = light.shadowCascadeNearZ[ cascade ];
		var farZ = light.shadowCascadeFarZ[ cascade ];
		var pointsFrustum = virtualLight.pointsFrustum;
		pointsFrustum[ 0 ].z = nearZ;
		pointsFrustum[ 1 ].z = nearZ;
		pointsFrustum[ 2 ].z = nearZ;
		pointsFrustum[ 3 ].z = nearZ;
		pointsFrustum[ 4 ].z = farZ;
		pointsFrustum[ 5 ].z = farZ;
		pointsFrustum[ 6 ].z = farZ;
		pointsFrustum[ 7 ].z = farZ;
	}
		function updateShadowCamera( camera, light ) {
		var shadowCamera = light.shadowCamera,
			pointsFrustum = light.pointsFrustum,
			pointsWorld = light.pointsWorld;
		_min.set( Infinity, Infinity, Infinity );
		_max.set( -Infinity, -Infinity, -Infinity );
		for ( var i = 0; i < 8; i ++ ) {
			var p = pointsWorld[ i ];
			p.copy( pointsFrustum[ i ] );
			THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera );
			p.applyMatrix4( shadowCamera.matrixWorldInverse );
			if ( p.x < _min.x ) _min.x = p.x;
			if ( p.x > _max.x ) _max.x = p.x;
			if ( p.y < _min.y ) _min.y = p.y;
			if ( p.y > _max.y ) _max.y = p.y;
			if ( p.z < _min.z ) _min.z = p.z;
			if ( p.z > _max.z ) _max.z = p.z;
		}
		shadowCamera.left = _min.x;
		shadowCamera.right = _max.x;
		shadowCamera.top = _max.y;
		shadowCamera.bottom = _min.y;
								shadowCamera.updateProjectionMatrix();
	}
			function getObjectMaterial( object ) {
		return object.material instanceof THREE.MeshFaceMaterial
			? object.material.materials[ 0 ]
			: object.material;
	};
};
THREE.ShadowMapPlugin.__projector = new THREE.Projector();
THREE.SpritePlugin = function () {
	var _gl, _renderer, _precision, _sprite = {};
	this.init = function ( renderer ) {
		_gl = renderer.context;
		_renderer = renderer;
		_precision = renderer.getPrecision();
		_sprite.vertices = new Float32Array( 8 + 8 );
		_sprite.faces    = new Uint16Array( 6 );
		var i = 0;
		_sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = -1;			_sprite.vertices[ i++ ] = 0;  _sprite.vertices[ i++ ] = 0;			_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = -1;			_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 0;			_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 1;			_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 1;			_sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = 1;			_sprite.vertices[ i++ ] = 0;  _sprite.vertices[ i++ ] = 1;			i = 0;
		_sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2;
		_sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3;
		_sprite.vertexBuffer  = _gl.createBuffer();
		_sprite.elementBuffer = _gl.createBuffer();
		_gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
		_gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW );
		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW );
		_sprite.program = createProgram( THREE.ShaderSprite[ "sprite" ], _precision );
		_sprite.attributes = {};
		_sprite.uniforms = {};
		_sprite.attributes.position           = _gl.getAttribLocation ( _sprite.program, "position" );
		_sprite.attributes.uv                 = _gl.getAttribLocation ( _sprite.program, "uv" );
		_sprite.uniforms.uvOffset             = _gl.getUniformLocation( _sprite.program, "uvOffset" );
		_sprite.uniforms.uvScale              = _gl.getUniformLocation( _sprite.program, "uvScale" );
		_sprite.uniforms.rotation             = _gl.getUniformLocation( _sprite.program, "rotation" );
		_sprite.uniforms.scale                = _gl.getUniformLocation( _sprite.program, "scale" );
		_sprite.uniforms.alignment            = _gl.getUniformLocation( _sprite.program, "alignment" );
		_sprite.uniforms.color                = _gl.getUniformLocation( _sprite.program, "color" );
		_sprite.uniforms.map                  = _gl.getUniformLocation( _sprite.program, "map" );
		_sprite.uniforms.opacity              = _gl.getUniformLocation( _sprite.program, "opacity" );
		_sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" );
		_sprite.uniforms.sizeAttenuation   	  = _gl.getUniformLocation( _sprite.program, "sizeAttenuation" );
		_sprite.uniforms.screenPosition    	  = _gl.getUniformLocation( _sprite.program, "screenPosition" );
		_sprite.uniforms.modelViewMatrix      = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" );
		_sprite.uniforms.projectionMatrix     = _gl.getUniformLocation( _sprite.program, "projectionMatrix" );
		_sprite.uniforms.fogType 		  	  = _gl.getUniformLocation( _sprite.program, "fogType" );
		_sprite.uniforms.fogDensity 		  = _gl.getUniformLocation( _sprite.program, "fogDensity" );
		_sprite.uniforms.fogNear 		  	  = _gl.getUniformLocation( _sprite.program, "fogNear" );
		_sprite.uniforms.fogFar 		  	  = _gl.getUniformLocation( _sprite.program, "fogFar" );
		_sprite.uniforms.fogColor 		  	  = _gl.getUniformLocation( _sprite.program, "fogColor" );
		_sprite.uniforms.alphaTest 		  	  = _gl.getUniformLocation( _sprite.program, "alphaTest" );
	};
	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
		var sprites = scene.__webglSprites,
			nSprites = sprites.length;
		if ( ! nSprites ) return;
		var attributes = _sprite.attributes,
			uniforms = _sprite.uniforms;
		var invAspect = viewportHeight / viewportWidth;
		var halfViewportWidth = viewportWidth * 0.5,
			halfViewportHeight = viewportHeight * 0.5;
				_gl.useProgram( _sprite.program );
		_gl.enableVertexAttribArray( attributes.position );
		_gl.enableVertexAttribArray( attributes.uv );
		_gl.disable( _gl.CULL_FACE );
		_gl.enable( _gl.BLEND );
		_gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
		_gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 );
		_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
		_gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
		_gl.activeTexture( _gl.TEXTURE0 );
		_gl.uniform1i( uniforms.map, 0 );
		var oldFogType = 0;
		var sceneFogType = 0;
		var fog = scene.fog;
		if ( fog ) {
			_gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
			if ( fog instanceof THREE.Fog ) {
				_gl.uniform1f( uniforms.fogNear, fog.near );
				_gl.uniform1f( uniforms.fogFar, fog.far );
				_gl.uniform1i( uniforms.fogType, 1 );
				oldFogType = 1;
				sceneFogType = 1;
			} else if ( fog instanceof THREE.FogExp2 ) {
				_gl.uniform1f( uniforms.fogDensity, fog.density );
				_gl.uniform1i( uniforms.fogType, 2 );
				oldFogType = 2;
				sceneFogType = 2;
			}
		} else {
			_gl.uniform1i( uniforms.fogType, 0 );
			oldFogType = 0;
			sceneFogType = 0;
		}
				var i, sprite, material, screenPosition, size, fogType, scale = [];
		for( i = 0; i < nSprites; i ++ ) {
			sprite = sprites[ i ];
			material = sprite.material;
			if ( ! sprite.visible || material.opacity === 0 ) continue;
			if ( ! material.useScreenCoordinates ) {
				sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
				sprite.z = - sprite._modelViewMatrix.elements[ 14 ];
			} else {
				sprite.z = - sprite.position.z;
			}
		}
		sprites.sort( painterSortStable );
				for( i = 0; i < nSprites; i ++ ) {
			sprite = sprites[ i ];
			material = sprite.material;
			if ( ! sprite.visible || material.opacity === 0 ) continue;
			if ( material.map && material.map.image && material.map.image.width ) {
				_gl.uniform1f( uniforms.alphaTest, material.alphaTest );
				if ( material.useScreenCoordinates === true ) {
					_gl.uniform1i( uniforms.useScreenCoordinates, 1 );
					_gl.uniform3f(
						uniforms.screenPosition,
						( ( sprite.position.x * _renderer.devicePixelRatio ) - halfViewportWidth  ) / halfViewportWidth,
						( halfViewportHeight - ( sprite.position.y * _renderer.devicePixelRatio ) ) / halfViewportHeight,
						Math.max( 0, Math.min( 1, sprite.position.z ) )
					);
					scale[ 0 ] = _renderer.devicePixelRatio;
					scale[ 1 ] = _renderer.devicePixelRatio;
				} else {
					_gl.uniform1i( uniforms.useScreenCoordinates, 0 );
					_gl.uniform1i( uniforms.sizeAttenuation, material.sizeAttenuation ? 1 : 0 );
					_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );
					scale[ 0 ] = 1;
					scale[ 1 ] = 1;
				}
				if ( scene.fog && material.fog ) {
					fogType = sceneFogType;
				} else {
					fogType = 0;
				}
				if ( oldFogType !== fogType ) {
					_gl.uniform1i( uniforms.fogType, fogType );
					oldFogType = fogType;
				}
				size = 1 / ( material.scaleByViewport ? viewportHeight : 1 );
				scale[ 0 ] *= size * invAspect * sprite.scale.x
				scale[ 1 ] *= size * sprite.scale.y;
				_gl.uniform2f( uniforms.uvScale, material.uvScale.x, material.uvScale.y );
				_gl.uniform2f( uniforms.uvOffset, material.uvOffset.x, material.uvOffset.y );
				_gl.uniform2f( uniforms.alignment, material.alignment.x, material.alignment.y );
				_gl.uniform1f( uniforms.opacity, material.opacity );
				_gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
				_gl.uniform1f( uniforms.rotation, sprite.rotation );
				_gl.uniform2fv( uniforms.scale, scale );
				_renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
				_renderer.setDepthTest( material.depthTest );
				_renderer.setDepthWrite( material.depthWrite );
				_renderer.setTexture( material.map, 0 );
				_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
			}
		}
				_gl.enable( _gl.CULL_FACE );
	};
	function createProgram ( shader, precision ) {
		var program = _gl.createProgram();
		var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
		var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
		var prefix = "precision " + precision + " float;\n";
		_gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
		_gl.shaderSource( vertexShader, prefix + shader.vertexShader );
		_gl.compileShader( fragmentShader );
		_gl.compileShader( vertexShader );
		_gl.attachShader( program, fragmentShader );
		_gl.attachShader( program, vertexShader );
		_gl.linkProgram( program );
		return program;
	};
	function painterSortStable ( a, b ) {
		if ( a.z !== b.z ) {
			return b.z - a.z;
		} else {
			return b.id - a.id;
		}
	};
};
THREE.DepthPassPlugin = function () {
	this.enabled = false;
	this.renderTarget = null;
	var _gl,
	_renderer,
	_depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
	_frustum = new THREE.Frustum(),
	_projScreenMatrix = new THREE.Matrix4();
	this.init = function ( renderer ) {
		_gl = renderer.context;
		_renderer = renderer;
		var depthShader = THREE.ShaderLib[ "depthRGBA" ];
		var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
		_depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
		_depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
		_depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } );
		_depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } );
		_depthMaterial._shadowPass = true;
		_depthMaterialMorph._shadowPass = true;
		_depthMaterialSkin._shadowPass = true;
		_depthMaterialMorphSkin._shadowPass = true;
	};
	this.render = function ( scene, camera ) {
		if ( ! this.enabled ) return;
		this.update( scene, camera );
	};
	this.update = function ( scene, camera ) {
		var i, il, j, jl, n,
		program, buffer, material,
		webglObject, object, light,
		renderList,
		fog = null;
				_gl.clearColor( 1, 1, 1, 1 );
		_gl.disable( _gl.BLEND );
		_renderer.setDepthTest( true );
				if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
				camera.matrixWorldInverse.getInverse( camera.matrixWorld );
		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
		_frustum.setFromMatrix( _projScreenMatrix );
				_renderer.setRenderTarget( this.renderTarget );
		_renderer.clear();
				renderList = scene.__webglObjects;
		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
			webglObject = renderList[ j ];
			object = webglObject.object;
			webglObject.render = false;
			if ( object.visible ) {
				if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
					object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
					webglObject.render = true;
				}
			}
		}
				var objectMaterial, useMorphing, useSkinning;
		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
			webglObject = renderList[ j ];
			if ( webglObject.render ) {
				object = webglObject.object;
				buffer = webglObject.buffer;
								if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue;
				objectMaterial = getObjectMaterial( object );
				if ( objectMaterial ) _renderer.setMaterialFaces( object.material );
				useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
				useSkinning = objectMaterial.skinning;
				if ( object.customDepthMaterial ) {
					material = object.customDepthMaterial;
				} else if ( useSkinning ) {
					material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
				} else if ( useMorphing ) {
					material = _depthMaterialMorph;
				} else {
					material = _depthMaterial;
				}
				if ( buffer instanceof THREE.BufferGeometry ) {
					_renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object );
				} else {
					_renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object );
				}
			}
		}
				renderList = scene.__webglObjectsImmediate;
		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
			webglObject = renderList[ j ];
			object = webglObject.object;
			if ( object.visible ) {
				object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
				_renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object );
			}
		}
				var clearColor = _renderer.getClearColor(),
		clearAlpha = _renderer.getClearAlpha();
		_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
		_gl.enable( _gl.BLEND );
	};
			function getObjectMaterial( object ) {
		return object.material instanceof THREE.MeshFaceMaterial
			? object.material.materials[ 0 ]
			: object.material;
	};
};
THREE.ShaderFlares = {
	'lensFlareVertexTexture': {
		vertexShader: [
			"uniform lowp int renderType;",
			"uniform vec3 screenPosition;",
			"uniform vec2 scale;",
			"uniform float rotation;",
			"uniform sampler2D occlusionMap;",
			"attribute vec2 position;",
			"attribute vec2 uv;",
			"varying vec2 vUV;",
			"varying float vVisibility;",
			"void main() {",
				"vUV = uv;",
				"vec2 pos = position;",
				"if( renderType == 2 ) {",
					"vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );",
					"visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",
					"vVisibility =        visibility.r / 9.0;",
					"vVisibility *= 1.0 - visibility.g / 9.0;",
					"vVisibility *=       visibility.b / 9.0;",
					"vVisibility *= 1.0 - visibility.a / 9.0;",
					"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
					"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
				"}",
				"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
			"}"
		].join( "\n" ),
		fragmentShader: [
			"uniform lowp int renderType;",
			"uniform sampler2D map;",
			"uniform float opacity;",
			"uniform vec3 color;",
			"varying vec2 vUV;",
			"varying float vVisibility;",
			"void main() {",
								"if( renderType == 0 ) {",
					"gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );",
								"} else if( renderType == 1 ) {",
					"gl_FragColor = texture2D( map, vUV );",
								"} else {",
					"vec4 texture = texture2D( map, vUV );",
					"texture.a *= opacity * vVisibility;",
					"gl_FragColor = texture;",
					"gl_FragColor.rgb *= color;",
				"}",
			"}"
		].join( "\n" )
	},
	'lensFlare': {
		vertexShader: [
			"uniform lowp int renderType;",
			"uniform vec3 screenPosition;",
			"uniform vec2 scale;",
			"uniform float rotation;",
			"attribute vec2 position;",
			"attribute vec2 uv;",
			"varying vec2 vUV;",
			"void main() {",
				"vUV = uv;",
				"vec2 pos = position;",
				"if( renderType == 2 ) {",
					"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
					"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
				"}",
				"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
			"}"
		].join( "\n" ),
		fragmentShader: [
			"precision mediump float;",
			"uniform lowp int renderType;",
			"uniform sampler2D map;",
			"uniform sampler2D occlusionMap;",
			"uniform float opacity;",
			"uniform vec3 color;",
			"varying vec2 vUV;",
			"void main() {",
								"if( renderType == 0 ) {",
					"gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );",
								"} else if( renderType == 1 ) {",
					"gl_FragColor = texture2D( map, vUV );",
								"} else {",
					"float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;",
					"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;",
					"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;",
					"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;",
					"visibility = ( 1.0 - visibility / 4.0 );",
					"vec4 texture = texture2D( map, vUV );",
					"texture.a *= opacity * visibility;",
					"gl_FragColor = texture;",
					"gl_FragColor.rgb *= color;",
				"}",
			"}"
		].join( "\n" )
	}
};
THREE.ShaderSprite = {
	'sprite': {
		vertexShader: [
			"uniform int useScreenCoordinates;",
			"uniform int sizeAttenuation;",
			"uniform vec3 screenPosition;",
			"uniform mat4 modelViewMatrix;",
			"uniform mat4 projectionMatrix;",
			"uniform float rotation;",
			"uniform vec2 scale;",
			"uniform vec2 alignment;",
			"uniform vec2 uvOffset;",
			"uniform vec2 uvScale;",
			"attribute vec2 position;",
			"attribute vec2 uv;",
			"varying vec2 vUV;",
			"void main() {",
				"vUV = uvOffset + uv * uvScale;",
				"vec2 alignedPosition = position + alignment;",
				"vec2 rotatedPosition;",
				"rotatedPosition.x = ( cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y ) * scale.x;",
				"rotatedPosition.y = ( sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y ) * scale.y;",
				"vec4 finalPosition;",
				"if( useScreenCoordinates != 0 ) {",
					"finalPosition = vec4( screenPosition.xy + rotatedPosition, screenPosition.z, 1.0 );",
				"} else {",
					"finalPosition = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );",
					"finalPosition.xy += rotatedPosition * ( sizeAttenuation == 1 ? 1.0 : finalPosition.z );",
				"}",
				"gl_Position = finalPosition;",
			"}"
		].join( "\n" ),
		fragmentShader: [
			"uniform vec3 color;",
			"uniform sampler2D map;",
			"uniform float opacity;",
			"uniform int fogType;",
			"uniform vec3 fogColor;",
			"uniform float fogDensity;",
			"uniform float fogNear;",
			"uniform float fogFar;",
			"uniform float alphaTest;",
			"varying vec2 vUV;",
			"void main() {",
				"vec4 texture = texture2D( map, vUV );",
				"if ( texture.a < alphaTest ) discard;",
				"gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );",
				"if ( fogType > 0 ) {",
					"float depth = gl_FragCoord.z / gl_FragCoord.w;",
					"float fogFactor = 0.0;",
					"if ( fogType == 1 ) {",
						"fogFactor = smoothstep( fogNear, fogFar, depth );",
					"} else {",
						"const float LOG2 = 1.442695;",
						"float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
						"fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
					"}",
					"gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",
				"}",
			"}"
		].join( "\n" )
	}
};
